diff --git a/pom.xml b/pom.xml
index 3c7d0d8b..cbcfe9e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
ca.gc.aafc
seqdb.api
- 2.19.0
+ 2.20
jar
seqdb-api
@@ -34,7 +34,7 @@
10.17.0
2.1.0
- 0.129
+ 0.134
false
diff --git a/src/main/java/ca/gc/aafc/seqdb/api/dto/RunSummaryDto.java b/src/main/java/ca/gc/aafc/seqdb/api/dto/RunSummaryDto.java
new file mode 100644
index 00000000..3d563ae6
--- /dev/null
+++ b/src/main/java/ca/gc/aafc/seqdb/api/dto/RunSummaryDto.java
@@ -0,0 +1,47 @@
+package ca.gc.aafc.seqdb.api.dto;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.toedter.spring.hateoas.jsonapi.JsonApiId;
+import com.toedter.spring.hateoas.jsonapi.JsonApiTypeForClass;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Singular;
+
+
+/**
+ * Store the summary information about a run and its related information
+ */
+@AllArgsConstructor
+@Getter
+@Builder
+@JsonApiTypeForClass(RunSummaryDto.TYPENAME)
+public class RunSummaryDto {
+
+ public static final String TYPENAME = "run-summary";
+
+ @JsonApiId
+ private UUID id;
+
+ private String name;
+
+ @Singular
+ private List items;
+
+ public record RunSummaryItem(UUID uuid, MolecularAnalysisResultSummary result, GenericMolecularAnalysisItemSummary genericMolecularAnalysisItemSummary) {
+ }
+
+ public record MolecularAnalysisResultSummary(UUID uuid, String type) {
+ }
+
+
+ public record GenericMolecularAnalysisItemSummary(UUID uuid, String name, GenericMolecularAnalysisSummary genericMolecularAnalysisSummary) {
+ }
+
+ public record GenericMolecularAnalysisSummary(UUID uuid, String name, String analysisType) {
+ }
+
+}
diff --git a/src/main/java/ca/gc/aafc/seqdb/api/repository/RunSummaryRepository.java b/src/main/java/ca/gc/aafc/seqdb/api/repository/RunSummaryRepository.java
new file mode 100644
index 00000000..ed567901
--- /dev/null
+++ b/src/main/java/ca/gc/aafc/seqdb/api/repository/RunSummaryRepository.java
@@ -0,0 +1,66 @@
+package ca.gc.aafc.seqdb.api.repository;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.RepresentationModel;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.toedter.spring.hateoas.jsonapi.JsonApiModelBuilder;
+
+import ca.gc.aafc.dina.filter.FilterExpression;
+import ca.gc.aafc.dina.filter.QueryStringParser;
+import ca.gc.aafc.dina.filter.QueryComponent;
+import ca.gc.aafc.seqdb.api.dto.RunSummaryDto;
+import ca.gc.aafc.seqdb.api.service.RunSummaryService;
+
+import static com.toedter.spring.hateoas.jsonapi.JsonApiModelBuilder.jsonApiModel;
+import static com.toedter.spring.hateoas.jsonapi.MediaTypes.JSON_API_VALUE;
+
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Objects;
+import javax.servlet.http.HttpServletRequest;
+
+@RestController
+@RequestMapping(value = "/api", produces = JSON_API_VALUE)
+public class RunSummaryRepository {
+
+ private final RunSummaryService runSummaryService;
+
+ public RunSummaryRepository(RunSummaryService runSummaryService) {
+ this.runSummaryService = runSummaryService;
+ }
+
+ @GetMapping(RunSummaryDto.TYPENAME)
+ public ResponseEntity> handleFindAll(HttpServletRequest req) {
+ String queryString = decodeQueryString(req);
+ QueryComponent queryComponents = QueryStringParser.parse(queryString);
+
+ if (queryComponents.getFilterExpression().isEmpty()) {
+ return ResponseEntity.badRequest().build();
+ }
+ FilterExpression filterExpression = queryComponents.getFilterExpression().get();
+ if ("".equals(filterExpression.attribute())) {
+ return ResponseEntity.badRequest().build();
+ }
+
+ List dtos = runSummaryService.findSummary(filterExpression);
+ JsonApiModelBuilder builder = jsonApiModel().model(CollectionModel.of(dtos));
+
+ return ResponseEntity.ok(builder.build());
+ }
+
+ protected static String decodeQueryString(HttpServletRequest req) {
+ Objects.requireNonNull(req);
+
+ if (StringUtils.isBlank(req.getQueryString())) {
+ return "";
+ }
+ return URLDecoder.decode(req.getQueryString(), StandardCharsets.UTF_8);
+ }
+
+}
diff --git a/src/main/java/ca/gc/aafc/seqdb/api/service/RunSummaryService.java b/src/main/java/ca/gc/aafc/seqdb/api/service/RunSummaryService.java
new file mode 100644
index 00000000..298e0fd3
--- /dev/null
+++ b/src/main/java/ca/gc/aafc/seqdb/api/service/RunSummaryService.java
@@ -0,0 +1,100 @@
+package ca.gc.aafc.seqdb.api.service;
+
+import org.springframework.stereotype.Service;
+
+import com.github.tennaito.rsql.misc.ArgumentParser;
+
+import ca.gc.aafc.dina.filter.DinaFilterArgumentParser;
+import ca.gc.aafc.dina.filter.FilterExpression;
+import ca.gc.aafc.dina.filter.SimpleFilterHandlerV2;
+import ca.gc.aafc.seqdb.api.dto.RunSummaryDto;
+import ca.gc.aafc.seqdb.api.entities.GenericMolecularAnalysis;
+import ca.gc.aafc.seqdb.api.entities.GenericMolecularAnalysisItem;
+import ca.gc.aafc.seqdb.api.entities.MolecularAnalysisRun;
+import ca.gc.aafc.seqdb.api.entities.MolecularAnalysisRunItem;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import javax.persistence.criteria.Predicate;
+import lombok.NonNull;
+
+@Service
+public class RunSummaryService {
+
+ private static final Set RELATIONSHIPS_TO_LOAD = Set.of(
+ "genericMolecularAnalysis", "molecularAnalysisRunItem", "molecularAnalysisRunItem.result");
+ private static final ArgumentParser RSQL_ARGUMENT_PARSER = new DinaFilterArgumentParser();
+
+ private final GenericMolecularAnalysisItemService genericMolecularAnalysisItemService;
+
+ public RunSummaryService(@NonNull GenericMolecularAnalysisItemService genericMolecularAnalysisItemService) {
+ this.genericMolecularAnalysisItemService = genericMolecularAnalysisItemService;
+ }
+
+ public List findSummary(FilterExpression filterExpression) {
+
+ List entities = genericMolecularAnalysisItemService.findAll(
+ GenericMolecularAnalysisItem.class,
+ (criteriaBuilder, root, em) -> {
+ Predicate restriction =
+ SimpleFilterHandlerV2.getRestriction(root, criteriaBuilder, RSQL_ARGUMENT_PARSER::parse,
+ em.getMetamodel(), List.of(filterExpression));
+ return new Predicate[] {restriction};
+ },
+ (cb, root) -> List.of(), 0, 100, Set.of(), RELATIONSHIPS_TO_LOAD);
+
+ // Collect all GenericMolecularAnalysis
+ Map uniqueGenericMolecularAnalysisRun = new HashMap<>(entities.size());
+ for (GenericMolecularAnalysisItem item : entities) {
+ // start with the MolecularAnalysisRun
+ if (hasAnalysisRunItemAndRun(item)) {
+ MolecularAnalysisRun molecularAnalysisRun = item.getMolecularAnalysisRunItem().getRun();
+ var builder =
+ uniqueGenericMolecularAnalysisRun.computeIfAbsent(molecularAnalysisRun.getUuid(),
+ u -> initBuilder(molecularAnalysisRun));
+ builder.item(createRunSummaryItem(item.getMolecularAnalysisRunItem(), item,
+ item.getGenericMolecularAnalysis()));
+ }
+ }
+
+ return uniqueGenericMolecularAnalysisRun.values().stream().map(
+ RunSummaryDto.RunSummaryDtoBuilder::build).toList();
+ }
+
+ /**
+ * Make sure the {@link GenericMolecularAnalysisItem} has a {@link MolecularAnalysisRunItem}
+ * and an associated {@link MolecularAnalysisRun}
+ * @param gmari
+ * @return
+ */
+ private static boolean hasAnalysisRunItemAndRun(GenericMolecularAnalysisItem gmari) {
+ return gmari.getMolecularAnalysisRunItem() != null &&
+ gmari.getMolecularAnalysisRunItem().getRun() != null;
+ }
+
+ private static RunSummaryDto.RunSummaryDtoBuilder initBuilder(MolecularAnalysisRun molecularAnalysisRun) {
+ return RunSummaryDto.builder()
+ .id(molecularAnalysisRun.getUuid())
+ .name(molecularAnalysisRun.getName());
+ }
+
+ private static RunSummaryDto.RunSummaryItem createRunSummaryItem(
+ MolecularAnalysisRunItem molecularAnalysisRunItem,
+ GenericMolecularAnalysisItem genericMolecularAnalysisItem,
+ GenericMolecularAnalysis genericMolecularAnalysis) {
+
+ RunSummaryDto.MolecularAnalysisResultSummary molecularAnalysisResultSummary =
+ molecularAnalysisRunItem.getResult() != null ?
+ new RunSummaryDto.MolecularAnalysisResultSummary(
+ molecularAnalysisRunItem.getResult().getUuid(), "") : null;
+
+ return new RunSummaryDto.RunSummaryItem(molecularAnalysisRunItem.getUuid(),
+ molecularAnalysisResultSummary, new RunSummaryDto.GenericMolecularAnalysisItemSummary(genericMolecularAnalysisItem.getUuid(),
+ molecularAnalysisRunItem.getName(),
+ new RunSummaryDto.GenericMolecularAnalysisSummary(genericMolecularAnalysis.getUuid(),
+ genericMolecularAnalysis.getName(), genericMolecularAnalysis.getAnalysisType())));
+ }
+}
diff --git a/src/main/java/ca/gc/aafc/seqdb/api/validation/SequenceManagedAttributeValueValidator.java b/src/main/java/ca/gc/aafc/seqdb/api/validation/SequenceManagedAttributeValueValidator.java
index 7b2185f7..e48b0545 100644
--- a/src/main/java/ca/gc/aafc/seqdb/api/validation/SequenceManagedAttributeValueValidator.java
+++ b/src/main/java/ca/gc/aafc/seqdb/api/validation/SequenceManagedAttributeValueValidator.java
@@ -2,7 +2,6 @@
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.context.MessageSource;
-import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
@@ -102,9 +101,4 @@ public Object getValue() {
return managedAttributeComponent;
}
}
-
- // to be replaced by dina-base whne 0.132 will be released
- private String getMessageForKey(String key, Object... objects) {
- return messageSource.getMessage(key, objects, LocaleContextHolder.getLocale());
- }
}