Skip to content

Commit

Permalink
#260 - Endpoint Modification for Template and savedQueries Retrieval …
Browse files Browse the repository at this point in the history
…with activated Validation

- change query and template endpoints to include getting invalid terms by default
- this will most likely change when validation is extended to also include missing contexts or invalid filters
  • Loading branch information
michael-82 committed Mar 19, 2024
1 parent d8d1cbc commit f6d09ee
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.numcodex.feasibility_gui_backend.common.api.TermCode;
import de.numcodex.feasibility_gui_backend.query.api.Query;
import de.numcodex.feasibility_gui_backend.query.api.QueryTemplate;
import de.numcodex.feasibility_gui_backend.query.api.SavedQuery;
Expand All @@ -14,6 +15,7 @@
import de.numcodex.feasibility_gui_backend.query.result.ResultService;
import de.numcodex.feasibility_gui_backend.query.templates.QueryTemplateException;
import de.numcodex.feasibility_gui_backend.query.templates.QueryTemplateHandler;
import de.numcodex.feasibility_gui_backend.terminology.validation.TermCodeValidation;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DataIntegrityViolationException;
Expand Down Expand Up @@ -58,6 +60,9 @@ public enum ResultDetail {
@NonNull
private final SavedQueryRepository savedQueryRepository;

@NonNull
private final TermCodeValidation termCodeValidation;

@NonNull
private ObjectMapper jsonUtil;

Expand Down Expand Up @@ -235,28 +240,44 @@ public String getAuthorId(Long queryId) throws QueryNotFoundException {
return queryRepository.getAuthor(queryId).orElseThrow(QueryNotFoundException::new);
}

public List<QueryListEntry> convertQueriesToQueryListEntries(List<de.numcodex.feasibility_gui_backend.query.persistence.Query> queryList) {
var ret = new ArrayList<QueryListEntry>();
public QueryListEntry convertQueryToQueryListEntry(de.numcodex.feasibility_gui_backend.query.persistence.Query query,
boolean skipValidation) {
List<TermCode> invalidTermCodes;
if (skipValidation) {
invalidTermCodes = List.of();
} else {
try {
var sq = jsonUtil.readValue(query.getQueryContent().getQueryContent(), StructuredQuery.class);
invalidTermCodes = termCodeValidation.getInvalidTermCodes(sq);
} catch (JsonProcessingException e) {
invalidTermCodes = List.of();
}
}

queryList.forEach(q -> {
if (q.getSavedQuery() != null) {
ret.add(
QueryListEntry.builder()
.id(q.getId())
.label(q.getSavedQuery().getLabel())
.comment(q.getSavedQuery().getComment())
.totalNumberOfPatients(q.getSavedQuery().getResultSize())
.createdAt(q.getCreatedAt())
.build());
} else {
ret.add(
QueryListEntry.builder()
.id(q.getId())
.createdAt(q.getCreatedAt())
.build());
}
});
if (query.getSavedQuery() != null) {
return
QueryListEntry.builder()
.id(query.getId())
.label(query.getSavedQuery().getLabel())
.comment(query.getSavedQuery().getComment())
.totalNumberOfPatients(query.getSavedQuery().getResultSize())
.createdAt(query.getCreatedAt())
.invalidTerms(invalidTermCodes)
.build();
} else {
return
QueryListEntry.builder()
.id(query.getId())
.createdAt(query.getCreatedAt())
.invalidTerms(invalidTermCodes)
.build();
}
}

public List<QueryListEntry> convertQueriesToQueryListEntries(List<de.numcodex.feasibility_gui_backend.query.persistence.Query> queryList,
boolean skipValidation) {
var ret = new ArrayList<QueryListEntry>();
queryList.forEach(q -> ret.add(convertQueryToQueryListEntry(q, skipValidation)));
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.numcodex.feasibility_gui_backend.common.api.TermCode;
import lombok.Builder;

import java.sql.Timestamp;
import java.util.List;

@JsonInclude(Include.NON_NULL)
@Builder
Expand All @@ -14,7 +16,8 @@ public record QueryListEntry(
@JsonProperty String label,
@JsonProperty String comment,
@JsonProperty Timestamp createdAt,
@JsonProperty Long totalNumberOfPatients
@JsonProperty Long totalNumberOfPatients,
@JsonProperty List<TermCode> invalidTerms
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,12 @@ private URI buildResultLocationUri(HttpServletRequest httpServletRequest,
@GetMapping("")
public List<QueryListEntry> getQueryList(
@RequestParam(name = "filter", required = false) String filter,
@RequestParam(value = "skipValidation", required = false, defaultValue = "false") boolean skipValidation,
Principal principal) {
var userId = principal.getName();
var savedOnly = (filter != null && filter.equalsIgnoreCase("saved"));
var queryList = queryHandlerService.getQueryListForAuthor(userId, savedOnly);
return queryHandlerService.convertQueriesToQueryListEntries(queryList);
return queryHandlerService.convertQueriesToQueryListEntries(queryList, skipValidation);
}

@PostMapping("/{id}/saved")
Expand Down Expand Up @@ -296,7 +297,7 @@ public List<QueryListEntry> getQueryListForUser(
@RequestParam(name = "filter", required = false) String filter) {
var savedOnly = (filter != null && filter.equalsIgnoreCase("saved"));
var queryList = queryHandlerService.getQueryListForAuthor(userId, savedOnly);
return queryHandlerService.convertQueriesToQueryListEntries(queryList);
return queryHandlerService.convertQueriesToQueryListEntries(queryList, true);
}

@GetMapping("/{id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,22 +97,31 @@ public ResponseEntity<Object> getQueryTemplate(@PathVariable(value = "queryId")
}

@GetMapping(path = "")
public ResponseEntity<Object> getQueryTemplates(Principal principal) {
public ResponseEntity<Object> getQueryTemplates(
@RequestParam(value = "skipValidation", required = false, defaultValue = "false") boolean skipValidation,
Principal principal) {

var queries = queryHandlerService.getQueryTemplatesForAuthor(principal.getName());
var ret = new ArrayList<QueryTemplate>();
queries.forEach(q -> {
try {
QueryTemplate convertedQuery = queryHandlerService.convertTemplatePersistenceToApi(q);
List<TermCode> invalidTermCodes;
if (skipValidation) {
invalidTermCodes = List.of();
} else {
invalidTermCodes = termCodeValidation.getInvalidTermCodes(
convertedQuery.content());
}
var convertedQueryWithoutContent = QueryTemplate.builder()
.id(convertedQuery.id())
.label(convertedQuery.label())
.comment(convertedQuery.comment())
.lastModified(convertedQuery.lastModified())
.createdBy(convertedQuery.createdBy())
.invalidTerms(convertedQuery.invalidTerms())
.isValid(convertedQuery.isValid())
.build();
.id(convertedQuery.id())
.label(convertedQuery.label())
.comment(convertedQuery.comment())
.lastModified(convertedQuery.lastModified())
.createdBy(convertedQuery.createdBy())
.invalidTerms(invalidTermCodes)
.isValid(convertedQuery.isValid())
.build();
ret.add(convertedQueryWithoutContent);
} catch (JsonProcessingException e) {
log.error("Error converting query");
Expand Down Expand Up @@ -143,32 +152,4 @@ public ResponseEntity<Object> deleteQueryTemplate(@PathVariable(value = "queryTe
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}

@GetMapping(path = "/validate")
public ResponseEntity<Object> validateTemplates(Principal principal) {

var queries = queryHandlerService.getQueryTemplatesForAuthor(principal.getName());
var ret = new ArrayList<QueryTemplate>();
queries.forEach(q -> {
try {
QueryTemplate convertedQuery = queryHandlerService.convertTemplatePersistenceToApi(q);
List<TermCode> invalidTermCodes = termCodeValidation.getInvalidTermCodes(
convertedQuery.content());
var convertedQueryWithoutContent = QueryTemplate.builder()
.id(convertedQuery.id())
.label(convertedQuery.label())
.comment(convertedQuery.comment())
.lastModified(convertedQuery.lastModified())
.createdBy(convertedQuery.createdBy())
.invalidTerms(invalidTermCodes)
.isValid(convertedQuery.isValid())
.build();
ret.add(convertedQueryWithoutContent);
} catch (JsonProcessingException e) {
log.error("Error converting query");
}
});
return new ResponseEntity<>(ret, HttpStatus.OK);
}

}
49 changes: 28 additions & 21 deletions src/main/resources/static/v3/api-docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ paths:
type: string
enum:
- saved
- name: skipValidation
in: query
description: If true, do not validate the query and do not include a list of invalid terms
required: false
schema:
type: boolean
default: false
responses:
200:
description: successful operation
Expand Down Expand Up @@ -505,6 +512,14 @@ paths:
summary: Read list of query templates
description: Returns the list of all query templates of the current user
operationId: getQueryTemplateList
parameters:
- name: skipValidation
in: query
description: If true, do not validate the query and do not include a list of invalid terms
required: false
schema:
type: boolean
default: false
responses:
200:
description: OK
Expand Down Expand Up @@ -612,27 +627,6 @@ paths:
security:
- feasibility_auth:
- user
/query/template/validate:
get:
tags:
- templates
summary: Check all own query templates for invalid or outdated termcodes
description: Returns a list of query templates with the additional info if a query is valid
operationId: validateQueryTemplateList
responses:
200:
description: OK
content:
application/json:
schema:
items:
$ref: '#/components/schemas/QueryTemplate'
401:
description: Unauthorized - please login first
content: { }
security:
- feasibility_auth:
- read:query
/terminology/categories:
get:
tags:
Expand Down Expand Up @@ -817,6 +811,7 @@ components:
required:
- id
- label
- invalidTerms
properties:
id:
type: integer
Expand All @@ -830,6 +825,10 @@ components:
format: 'date-time'
totalNumberOfPatients:
type: integer
invalidTerms:
type: array
items:
$ref: "#/components/schemas/TermCode"
Query:
type: object
required:
Expand Down Expand Up @@ -912,6 +911,7 @@ components:
type: object
required:
- label
- invalidTerms
properties:
id:
type: integer
Expand All @@ -930,6 +930,13 @@ components:
createdBy:
type: string
description: Keycloak id of the user who created the query
invalidTerms:
type: array
items:
$ref: "#/components/schemas/TermCode"
isValid:
type: boolean
description: is the query valid?
QueryTemplate:
type: object
required:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,17 @@
import java.net.URI;
import java.util.List;

import de.numcodex.feasibility_gui_backend.terminology.validation.TermCodeValidation;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.mockito.Spy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DataIntegrityViolationException;
import org.testcontainers.junit.jupiter.Testcontainers;
Expand Down Expand Up @@ -100,6 +101,9 @@ public class QueryHandlerServiceIT {
@Autowired
private QueryHashCalculator queryHashCalculator;

@MockBean
private TermCodeValidation termCodeValidation;

@Autowired
@Qualifier("translation")
private ObjectMapper jsonUtil;
Expand Down
Loading

0 comments on commit f6d09ee

Please sign in to comment.