Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
cgendreau committed Feb 6, 2025
2 parents 025dc00 + 8e95461 commit d4f79c6
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 8 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<groupId>ca.gc.aafc</groupId>
<artifactId>seqdb.api</artifactId>
<version>2.19.0</version>
<version>2.20</version>
<packaging>jar</packaging>

<name>seqdb-api</name>
Expand Down Expand Up @@ -34,7 +34,7 @@
<checkstyle.version>10.17.0</checkstyle.version>

<asciidoctor-maven-plugin.version>2.1.0</asciidoctor-maven-plugin.version>
<dina-base-api.version>0.129</dina-base-api.version>
<dina-base-api.version>0.134</dina-base-api.version>

<spring-boot-maven-plugin.fork>false</spring-boot-maven-plugin.fork>

Expand Down
47 changes: 47 additions & 0 deletions src/main/java/ca/gc/aafc/seqdb/api/dto/RunSummaryDto.java
Original file line number Diff line number Diff line change
@@ -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<RunSummaryItem> 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) {
}

}
Original file line number Diff line number Diff line change
@@ -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<RepresentationModel<?>> 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<RunSummaryDto> 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);
}

}
100 changes: 100 additions & 0 deletions src/main/java/ca/gc/aafc/seqdb/api/service/RunSummaryService.java
Original file line number Diff line number Diff line change
@@ -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<String> 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<RunSummaryDto> findSummary(FilterExpression filterExpression) {

List<GenericMolecularAnalysisItem> 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<UUID, RunSummaryDto.RunSummaryDtoBuilder> 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())));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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());
}
}

0 comments on commit d4f79c6

Please sign in to comment.