Skip to content

Commit ebebf7b

Browse files
authored
Dev catch json marshalling errors and fix cr-find error handler (#207)
* catch json marshalling errors and fix error handlers for the cr-find api * catch json marshalling errors and fix error handlers for the cr-find api
1 parent 7203d70 commit ebebf7b

File tree

12 files changed

+608
-517
lines changed

12 files changed

+608
-517
lines changed

JeMPI_Apps/JeMPI_LibAPI/src/main/java/org/jembi/jempi/libapi/Routes.java

+381-369
Large diffs are not rendered by default.

JeMPI_Apps/JeMPI_LibMPI/src/main/java/org/jembi/jempi/libmpi/LibMPI.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public List<GoldenRecord> findMatchCandidates(final CustomDemographicData demogr
165165
return client.findMatchCandidates(demographicData);
166166
}
167167

168-
public List<GoldenRecord> findGoldenRecords(final ApiModels.ApiCrFindRequest request) {
168+
public Either<List<GoldenRecord>, MpiGeneralError> findGoldenRecords(final ApiModels.ApiCrFindRequest request) {
169169
return client.findGoldenRecords(request);
170170
}
171171

JeMPI_Apps/JeMPI_LibMPI/src/main/java/org/jembi/jempi/libmpi/LibMPIClientInterface.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ PaginatedGIDsWithInteractionCount filterGidsWithInteractionCount(
9898
LocalDateTime createdAt,
9999
PaginationOptions paginationOptions);
100100

101-
List<GoldenRecord> findGoldenRecords(ApiModels.ApiCrFindRequest request);
101+
Either<List<GoldenRecord>, MpiGeneralError> findGoldenRecords(ApiModels.ApiCrFindRequest request);
102102

103103
/*
104104
* *****************************************************************************

JeMPI_Apps/JeMPI_LibMPI/src/main/java/org/jembi/jempi/libmpi/MpiServiceError.java

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ record CRClientExistsError(
4040
CustomDemographicData request) implements MpiServiceError {
4141
}
4242

43+
record InvalidFunctionError(
44+
String error
45+
) implements MpiServiceError {
46+
}
47+
48+
record InvalidOperatorError(
49+
String error
50+
) implements MpiServiceError {
51+
}
52+
4353
record CRUpdateFieldError(
4454
String goldenId,
4555
List<String> fields) implements MpiServiceError {
@@ -52,4 +62,5 @@ record CandidatesNotFoundError(
5262
String error,
5363
String interactionID) implements MpiServiceError {
5464
}
65+
5566
}

JeMPI_Apps/JeMPI_LibMPI/src/main/java/org/jembi/jempi/libmpi/dgraph/DgraphQueries.java

+110-58
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import org.apache.commons.lang3.StringUtils;
77
import org.apache.logging.log4j.LogManager;
88
import org.apache.logging.log4j.Logger;
9+
import org.jembi.jempi.libmpi.MpiGeneralError;
10+
import org.jembi.jempi.libmpi.MpiServiceError;
911
import org.jembi.jempi.shared.models.*;
1012
import org.jembi.jempi.shared.utils.AppUtils;
1113

@@ -363,8 +365,8 @@ private static HashMap<String, String> getCustomSearchQueryVariables(final List<
363365
}
364366

365367
private static String getSimpleSearchQueryFilters(
366-
final RecordType recordType,
367-
final List<ApiModels.ApiSearchParameter> parameters) {
368+
final RecordType recordType,
369+
final List<ApiModels.ApiSearchParameter> parameters) {
368370
List<String> gqlFilters = new ArrayList<>();
369371
for (ApiModels.ApiSearchParameter param : parameters) {
370372
if (!param.value().isEmpty()) {
@@ -374,15 +376,15 @@ private static String getSimpleSearchQueryFilters(
374376
if (distance == -1) {
375377
if (value.contains("_")) {
376378
gqlFilters.add("ge(" + recordType + "." + fieldName + ", \"" + value.substring(0, value.indexOf("_"))
377-
+ "\") AND le("
378-
+ recordType + "." + fieldName + ", \"" + value.substring(value.indexOf("_") + 1) + "\")");
379+
+ "\") AND le("
380+
+ recordType + "." + fieldName + ", \"" + value.substring(value.indexOf("_") + 1) + "\")");
379381
} else {
380382
gqlFilters.add("le(" + recordType + "." + fieldName + ", \"" + value + "\")");
381383
}
382384
} else if (distance == 0) {
383385
if (value.contains("_")) {
384386
gqlFilters.add(
385-
"eq(" + recordType + "." + fieldName + ", \"" + value.substring(0, value.indexOf("_")) + "\")");
387+
"eq(" + recordType + "." + fieldName + ", \"" + value.substring(0, value.indexOf("_")) + "\")");
386388
} else {
387389
gqlFilters.add("eq(" + recordType + "." + fieldName + ", \"" + value + "\")");
388390
}
@@ -605,66 +607,116 @@ static DgraphInteractions customSearchInteractions(
605607
return searchInteractions(gqlFilters, gqlArgs, gqlVars, offset, limit, sortBy, sortAsc);
606608
}
607609

608-
static DgraphGoldenRecords findGoldenRecords(final ApiModels.ApiCrFindRequest req) {
610+
static Either<DgraphGoldenRecords, MpiGeneralError> findGoldenRecords(final ApiModels.ApiCrFindRequest req) {
611+
final var setFunctions = new HashSet<String>();
612+
setFunctions.add("eq");
613+
setFunctions.add("match");
614+
final var setOperators = new HashSet<String>();
615+
setOperators.add("and");
616+
setOperators.add("or");
617+
try {
618+
final var operand = req.operand();
619+
final var queryBuilder = new StringBuilder("query query_1 ($").append(camelToSnake(operand.name())).append(":string");
620+
if (req.operands() != null) {
621+
for (ApiModels.ApiCrFindRequest.ApiLogicalOperand op2 : req.operands()) {
622+
queryBuilder.append(", $").append(camelToSnake(op2.operand().name())).append(":string");
623+
}
624+
}
625+
queryBuilder.append(") {\n\n");
626+
char alias = 'A';
627+
if (!setFunctions.contains(operand.fn())) {
628+
throw new InvalidFunctionException(String.format("Invalid function: %s", operand.fn()));
629+
}
630+
if (operand.fn().equals("match")) {
631+
if (operand.distance() == null) {
632+
throw new InvalidFunctionException("no distance parameter");
633+
} else if (operand.distance() < 0 || operand.distance() > 5) {
634+
throw new InvalidFunctionException(String.format("distance error: 0 < %d <= 5", operand.distance()));
635+
}
636+
}
637+
queryBuilder.append(" var(func:type(GoldenRecord)) @filter(")
638+
.append(operand.fn())
639+
.append("(GoldenRecord.")
640+
.append(camelToSnake(operand.name()))
641+
.append(", $")
642+
.append(camelToSnake(operand.name()))
643+
.append(operand.fn().equals("match")
644+
? String.format(Locale.ROOT, ", %d", operand.distance())
645+
: "")
646+
.append(")) {\n ")
647+
.append(alias)
648+
.append(" as uid\n }\n\n");
649+
650+
if (req.operands() != null) {
651+
for (ApiModels.ApiCrFindRequest.ApiLogicalOperand o : req.operands()) {
652+
if (!setFunctions.contains(o.operand().fn())) {
653+
throw new InvalidFunctionException(String.format("Invalid function: %s", o.operand().fn()));
654+
}
655+
if (o.operand().fn().equals("match")) {
656+
if (o.operand().distance() == null) {
657+
throw new InvalidFunctionException("no distance parameter");
658+
} else if (o.operand().distance() < 0 || o.operand().distance() > 5) {
659+
throw new InvalidFunctionException(String.format("distance error: 0 < %d <= 5", o.operand().distance()));
660+
}
661+
}
662+
if (!setOperators.contains(o.operator())) {
663+
throw new InvalidOperatorException(String.format("Invalid operator: %s", o.operator()));
664+
}
665+
queryBuilder.append(" var(func:type(GoldenRecord)) @filter(")
666+
.append(o.operand().fn())
667+
.append("(GoldenRecord.")
668+
.append(camelToSnake(o.operand().name()))
669+
.append(", $")
670+
.append(camelToSnake(o.operand().name()))
671+
.append(o.operand().fn().equals("match")
672+
? String.format(Locale.ROOT, ", %d", o.operand().distance())
673+
: "")
674+
.append(")) {\n ")
675+
.append(++alias)
676+
.append(" as uid\n }\n\n");
677+
}
678+
}
609679

610-
final var op = req.operand();
611-
StringBuilder queryBuilder = new StringBuilder("query query_1 ($").append(camelToSnake(op.name())).append(":string");
612-
if (req.operands() != null) {
613-
for (ApiModels.ApiCrFindRequest.ApiLogicalOperand op2 : req.operands()) {
614-
queryBuilder.append(", $").append(camelToSnake(op2.operand().name())).append(":string");
680+
alias = 'A';
681+
queryBuilder.append(" all(func:type(GoldenRecord)) @filter(uid(A)");
682+
if (req.operands() != null) {
683+
for (ApiModels.ApiCrFindRequest.ApiLogicalOperand o : req.operands()) {
684+
queryBuilder.append(" ").append(o.operator()).append(" uid(").append(++alias).append(")");
685+
}
615686
}
616-
}
617-
queryBuilder.append(") {\n\n");
618-
char alias = 'A';
619-
queryBuilder.append(" var(func:type(GoldenRecord)) @filter(")
620-
.append(op.fn())
621-
.append("(GoldenRecord.")
622-
.append(camelToSnake(op.name()))
623-
.append(", $")
624-
.append(camelToSnake(op.name()))
625-
.append(op.fn().equals("match")
626-
? String.format(Locale.ROOT, ", %d", op.distance())
627-
: "")
628-
.append(")) {\n ")
629-
.append(alias)
630-
.append(" as uid\n }\n\n");
631-
632-
if (req.operands() != null) {
633-
for (ApiModels.ApiCrFindRequest.ApiLogicalOperand o : req.operands()) {
634-
queryBuilder.append(" var(func:type(GoldenRecord)) @filter(")
635-
.append(o.operand().fn())
636-
.append("(GoldenRecord.")
637-
.append(camelToSnake(o.operand().name()))
638-
.append(", $")
639-
.append(camelToSnake(o.operand().name()))
640-
.append(o.operand().fn().equals("match")
641-
? String.format(Locale.ROOT, ", %d", o.operand().distance())
642-
: "")
643-
.append(")) {\n ")
644-
.append(++alias)
645-
.append(" as uid\n }\n\n");
687+
queryBuilder.append(") {\n").append(GOLDEN_RECORD_FIELD_NAMES).append(" }\n}\n");
688+
final var query = queryBuilder.toString();
689+
final var map = new HashMap<String, String>();
690+
map.put("$" + camelToSnake(operand.name()), operand.value());
691+
for (var o : req.operands()) {
692+
map.put("$" + camelToSnake(o.operand().name()), o.operand().value());
646693
}
694+
LOGGER.debug("%n{}", query);
695+
LOGGER.debug("{}", map);
696+
697+
698+
final var dgraphGoldenRecords = runGoldenRecordsQuery(query, map);
699+
LOGGER.debug("{}", dgraphGoldenRecords);
700+
return Either.left(dgraphGoldenRecords);
701+
} catch (InvalidFunctionException e) {
702+
LOGGER.error(e.getLocalizedMessage(), e);
703+
return Either.right(new MpiServiceError.InvalidFunctionError(e.getMessage()));
704+
} catch (InvalidOperatorException e) {
705+
LOGGER.error(e.getLocalizedMessage(), e);
706+
return Either.right(new MpiServiceError.InvalidOperatorError(e.getLocalizedMessage()));
647707
}
708+
}
648709

649-
alias = 'A';
650-
queryBuilder.append(" all(func:type(GoldenRecord)) @filter(uid(A)");
651-
if (req.operands() != null) {
652-
for (ApiModels.ApiCrFindRequest.ApiLogicalOperand o : req.operands()) {
653-
queryBuilder.append(" ").append(o.operator()).append(" uid(").append(++alias).append(")");
654-
}
710+
private static class InvalidFunctionException extends Exception {
711+
InvalidFunctionException(final String errorMessage) {
712+
super(errorMessage);
655713
}
656-
queryBuilder.append(") {\n").append(GOLDEN_RECORD_FIELD_NAMES).append(" }\n}\n");
657-
final var query = queryBuilder.toString();
658-
final var map = new HashMap<String, String>();
659-
map.put("$" + camelToSnake(op.name()), op.value());
660-
for (var o : req.operands()) {
661-
map.put("$" + camelToSnake(o.operand().name()), o.operand().value());
714+
}
715+
716+
private static class InvalidOperatorException extends Exception {
717+
InvalidOperatorException(final String errorMessage) {
718+
super(errorMessage);
662719
}
663-
LOGGER.debug("{}", "\n" + query);
664-
LOGGER.debug("{}", map);
665-
final var dgraphGoldenRecords = runGoldenRecordsQuery(query, map);
666-
LOGGER.debug("{}", dgraphGoldenRecords);
667-
return dgraphGoldenRecords;
668720
}
669721

670722

JeMPI_Apps/JeMPI_LibMPI/src/main/java/org/jembi/jempi/libmpi/dgraph/LibDgraph.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,13 @@ public List<GoldenRecord> findMatchCandidates(final CustomDemographicData demogr
9898
return candidates.stream().map(CustomDgraphGoldenRecord::toGoldenRecord).toList();
9999
}
100100

101-
public List<GoldenRecord> findGoldenRecords(final ApiModels.ApiCrFindRequest request) {
101+
public Either<List<GoldenRecord>, MpiGeneralError> findGoldenRecords(final ApiModels.ApiCrFindRequest request) {
102102
final var goldenRecords = DgraphQueries.findGoldenRecords(request);
103-
return goldenRecords.all().stream().map(CustomDgraphGoldenRecord::toGoldenRecord).toList();
103+
if (goldenRecords.isLeft()) {
104+
return Either.left(goldenRecords.getLeft().all().stream().map(CustomDgraphGoldenRecord::toGoldenRecord).toList());
105+
} else {
106+
return Either.right(goldenRecords.swap().getLeft());
107+
}
104108
}
105109

106110
private LibMPIPaginatedResultSet<ExpandedGoldenRecord> paginatedExpandedGoldenRecords(

JeMPI_Apps/JeMPI_LibMPI/src/main/java/org/jembi/jempi/libmpi/postgresql/LibPostgresql.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ public List<GoldenRecord> findMatchCandidates(final CustomDemographicData demogr
134134
return List.of();
135135
}
136136

137-
public List<GoldenRecord> findGoldenRecords(final ApiModels.ApiCrFindRequest request) {
137+
public Either<List<GoldenRecord>, MpiGeneralError> findGoldenRecords(final ApiModels.ApiCrFindRequest request) {
138138
LOGGER.error("Not implemented");
139-
return Collections.emptyList();
139+
return Either.left(Collections.emptyList());
140140
}
141141

142142
public LibMPIPaginatedResultSet<ExpandedGoldenRecord> simpleSearchGoldenRecords(

JeMPI_Apps/JeMPI_LibShared/src/main/java/org/jembi/jempi/shared/models/GlobalConstants.java

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public final class GlobalConstants {
7878

7979
public static final String DEFAULT_LINKER_GLOBAL_STORE_NAME = "linker";
8080
public static final StatusCode IM_A_TEA_POT = StatusCodes.IM_A_TEAPOT;
81+
public static final String IM_A_TEA_POT_LOG = "IM_A_TEA_POT";
8182

8283
public enum AuditEventType {
8384
LINKING_EVENT,

0 commit comments

Comments
 (0)