Skip to content

Commit

Permalink
Merge pull request #252 from AAFC-BICoE/35277_add_quality_control_sample
Browse files Browse the repository at this point in the history
35277 add quality control sample
  • Loading branch information
brandonandre authored Dec 4, 2024
2 parents bae372f + f9e2b76 commit e4796a3
Show file tree
Hide file tree
Showing 18 changed files with 414 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
@PropertySource(value = "classpath:vocabulary/pcrBatchType.yml", factory = YamlPropertyLoaderFactory.class)
@PropertySource(value = "classpath:vocabulary/sequencingType.yml", factory = YamlPropertyLoaderFactory.class)
@PropertySource(value = "classpath:vocabulary/molecularAnalysisType.yml", factory = YamlPropertyLoaderFactory.class)
@PropertySource(value = "classpath:vocabulary/qualityControlType.yml", factory = YamlPropertyLoaderFactory.class)
@ConfigurationProperties
@Validated
public class SequenceVocabularyConfiguration extends VocabularyConfiguration<VocabularyElementConfiguration> {

public static final String PCR_BATCH_TYPE_VOCAB_KEY = "pcrBatchType";
public static final String SEQUENCING_TYPE_VOCAB_KEY = "sequencingType";
public static final String MOLECULAR_ANALYSIS_TYPE_VOCAB_KEY = "molecularAnalysisType";
public static final String QUALITY_CONTROL_TYPE_VOCAB_KEY = "qualityControlType";

public SequenceVocabularyConfiguration(Map<String, List<VocabularyElementConfiguration>> vocabulary) {
super(vocabulary);
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/ca/gc/aafc/seqdb/api/dto/QualityControlDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package ca.gc.aafc.seqdb.api.dto;

import io.crnk.core.resource.annotations.JsonApiId;
import io.crnk.core.resource.annotations.JsonApiRelation;
import io.crnk.core.resource.annotations.JsonApiResource;
import java.time.OffsetDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import org.javers.core.metamodel.annotation.Id;
import org.javers.core.metamodel.annotation.PropertyName;
import org.javers.core.metamodel.annotation.TypeName;

import ca.gc.aafc.dina.dto.RelatedEntity;
import ca.gc.aafc.seqdb.api.entities.QualityControl;

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonApiResource(type = QualityControlDto.TYPENAME)
@TypeName(QualityControlDto.TYPENAME)
@RelatedEntity(QualityControl.class)
public class QualityControlDto {

public static final String TYPENAME = "quality-control";

@JsonApiId
@Id
@PropertyName("id")
private UUID uuid;

private String createdBy;
private OffsetDateTime createdOn;

private String group;

private String name;

private String qcType;

@JsonApiRelation
private MolecularAnalysisRunItemDto molecularAnalysisRunItem;

}
70 changes: 70 additions & 0 deletions src/main/java/ca/gc/aafc/seqdb/api/entities/QualityControl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package ca.gc.aafc.seqdb.api.entities;

import java.time.OffsetDateTime;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;
import org.hibernate.annotations.NaturalId;

import ca.gc.aafc.dina.entity.DinaEntity;

@Getter
@Entity
@Builder
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "quality_control")
public class QualityControl implements DinaEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

@NotNull
@NaturalId
private UUID uuid;

@NotBlank
@Column(name = "created_by", updatable = false)
private String createdBy;

@Column(name = "created_on", insertable = false, updatable = false)
@Generated(value = GenerationTime.INSERT)
private OffsetDateTime createdOn;

@Column(name = "_group")
private String group;

@NotBlank
@Size(max = 100)
private String name;

@NotBlank
@Size(max = 50)
@Column(name = "qc_type")
private String qcType;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "molecular_analysis_run_item_id")
private MolecularAnalysisRunItem molecularAnalysisRunItem;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ca.gc.aafc.seqdb.api.repository;

import org.springframework.boot.info.BuildProperties;
import org.springframework.stereotype.Repository;

import com.fasterxml.jackson.databind.ObjectMapper;

import ca.gc.aafc.dina.mapper.DinaMapper;
import ca.gc.aafc.dina.repository.DinaRepository;
import ca.gc.aafc.dina.repository.external.ExternalResourceProvider;
import ca.gc.aafc.dina.security.DinaAuthenticatedUser;
import ca.gc.aafc.dina.security.auth.DinaAuthorizationService;
import ca.gc.aafc.seqdb.api.dto.QualityControlDto;
import ca.gc.aafc.seqdb.api.entities.QualityControl;
import ca.gc.aafc.seqdb.api.service.QualityControlService;

import java.util.Optional;
import lombok.NonNull;

@Repository
public class QualityControlRepository extends DinaRepository<QualityControlDto, QualityControl> {

private Optional<DinaAuthenticatedUser> dinaAuthenticatedUser;

public QualityControlRepository(
@NonNull QualityControlService dinaService,
DinaAuthorizationService groupAuthorizationService,
@NonNull BuildProperties props,
ExternalResourceProvider externalResourceProvider,
Optional<DinaAuthenticatedUser> dinaAuthenticatedUser,
ObjectMapper objMapper) {
super(
dinaService,
groupAuthorizationService,
Optional.empty(),
new DinaMapper<>(QualityControlDto.class),
QualityControlDto.class,
QualityControl.class,
null,
externalResourceProvider,
props, objMapper);

this.dinaAuthenticatedUser = dinaAuthenticatedUser;
}

@Override
public <S extends QualityControlDto> S create(S resource) {
dinaAuthenticatedUser.ifPresent(
authenticatedUser -> resource.setCreatedBy(authenticatedUser.getUsername()));
return super.create(resource);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ca.gc.aafc.seqdb.api.service;

import lombok.NonNull;

import org.springframework.stereotype.Service;
import org.springframework.validation.SmartValidator;

import ca.gc.aafc.dina.jpa.BaseDAO;
import ca.gc.aafc.dina.service.DefaultDinaService;
import ca.gc.aafc.dina.util.UUIDHelper;
import ca.gc.aafc.seqdb.api.entities.QualityControl;
import ca.gc.aafc.seqdb.api.validation.QualityControlVocabularyValidator;

@Service
public class QualityControlService extends DefaultDinaService<QualityControl> {

private final QualityControlVocabularyValidator qualityControlVocabularyValidator;

public QualityControlService(
@NonNull BaseDAO baseDAO,
QualityControlVocabularyValidator qualityControlVocabularyValidator,
@NonNull SmartValidator sv) {
super(baseDAO, sv);
this.qualityControlVocabularyValidator = qualityControlVocabularyValidator;
}

@Override
protected void preCreate(QualityControl entity) {
entity.setUuid(UUIDHelper.generateUUIDv7());
}

@Override
public void validateBusinessRules(QualityControl entity) {
applyBusinessRule(entity, qualityControlVocabularyValidator);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public class PcrBatchVocabularyValidator extends VocabularyBasedValidator<PcrBat
private final List<VocabularyElementConfiguration> batchTypeVocabulary;

PcrBatchVocabularyValidator(MessageSource messageSource, SequenceVocabularyConfiguration vocabularyConfiguration) {
super(messageSource, PcrBatch.class);
super(PcrBatch.class, messageSource);
batchTypeVocabulary = vocabularyConfiguration.getVocabularyByKey(SequenceVocabularyConfiguration.PCR_BATCH_TYPE_VOCAB_KEY);
}

@Override
protected void validateVocabularyBasedAttribute(PcrBatch target, Errors errors) {
public void validateTarget(PcrBatch target, Errors errors) {
if (StringUtils.isBlank(target.getBatchType())) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ca.gc.aafc.seqdb.api.validation;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

import ca.gc.aafc.dina.vocabulary.VocabularyElementConfiguration;
import ca.gc.aafc.seqdb.api.SequenceVocabularyConfiguration;
import ca.gc.aafc.seqdb.api.entities.QualityControl;

@Component
public class QualityControlVocabularyValidator extends VocabularyBasedValidator<QualityControl> {

private static final String QUALITY_CONTROL_FIELD_NAME = "qcType";
private final List<VocabularyElementConfiguration> qcTypeVocabulary;

QualityControlVocabularyValidator(MessageSource messageSource, SequenceVocabularyConfiguration vocabularyConfiguration) {
super(QualityControl.class, messageSource);
qcTypeVocabulary = vocabularyConfiguration.getVocabularyByKey(SequenceVocabularyConfiguration.QUALITY_CONTROL_TYPE_VOCAB_KEY);
}

@Override
public void validateTarget(QualityControl target, Errors errors) {
if (StringUtils.isBlank(target.getQcType())) {
return;
}

target.setQcType(validateAndStandardizeValueAgainstVocabulary(target.getQcType(),
QUALITY_CONTROL_FIELD_NAME, qcTypeVocabulary, errors));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public class SeqBatchVocabularyValidator extends VocabularyBasedValidator<SeqBat
private final List<VocabularyElementConfiguration> sequencingTypeVocabulary;

SeqBatchVocabularyValidator(MessageSource messageSource, SequenceVocabularyConfiguration vocabularyConfiguration) {
super(messageSource, SeqBatch.class);
super(SeqBatch.class, messageSource);
sequencingTypeVocabulary = vocabularyConfiguration.getVocabularyByKey(SequenceVocabularyConfiguration.SEQUENCING_TYPE_VOCAB_KEY);
}

@Override
protected void validateVocabularyBasedAttribute(SeqBatch target, Errors errors) {
public void validateTarget(SeqBatch target, Errors errors) {
if (StringUtils.isBlank(target.getSequencingType())) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,23 @@
package ca.gc.aafc.seqdb.api.validation;

import java.util.List;
import java.util.Optional;

import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

import ca.gc.aafc.dina.validation.DinaBaseValidator;
import ca.gc.aafc.dina.vocabulary.VocabularyElementConfiguration;

import java.util.List;
import java.util.Optional;

/**
* Move to dina-base
*/
abstract class VocabularyBasedValidator <T> implements Validator {
abstract class VocabularyBasedValidator <T> extends DinaBaseValidator<T> {

public static final String VALUE_NOT_IN_VOCABULARY = "validation.constraint.violation.notInVocabulary";

private final MessageSource messageSource;
private final Class<T> supportedClass;

VocabularyBasedValidator(MessageSource messageSource, Class<T> supportedClass) {
this.messageSource = messageSource;
this.supportedClass = supportedClass;
}

@Override
public boolean supports(Class<?> clazz) {
return supportedClass.isAssignableFrom(clazz);
}

@Override
public void validate(Object target, Errors errors) {
if (!supports(target.getClass())) {
throw new IllegalArgumentException("VocabularyBasedValidator not supported for class " + target.getClass());
}
validateVocabularyBasedAttribute(supportedClass.cast(target), errors);
VocabularyBasedValidator(Class<T> supportedClass, MessageSource messageSource) {
super(supportedClass, messageSource);
}

/**
Expand Down Expand Up @@ -67,14 +49,4 @@ protected String validateAndStandardizeValueAgainstVocabulary(String value, Stri
protected Optional<VocabularyElementConfiguration> findInVocabulary(String value, List<VocabularyElementConfiguration> vocabularyElements) {
return vocabularyElements.stream().filter(o -> o.getKey().equalsIgnoreCase(value)).findFirst();
}

protected abstract void validateVocabularyBasedAttribute(T target, Errors errors);

protected String getMessage(String key) {
return messageSource.getMessage(key, null, LocaleContextHolder.getLocale());
}
protected String getMessage(String key, Object... messageArgs) {
return messageSource.getMessage(key, messageArgs, LocaleContextHolder.getLocale());
}

}
1 change: 1 addition & 0 deletions src/main/resources/db/changelog/db.changelog-master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,5 @@
<include file="db/changelog/migrations/54-Add_metagenomics_tables.xml"/>
<include file="db/changelog/migrations/55-Add_managed_attribute.xml"/>
<include file="db/changelog/migrations/56-Add_managed_attribute_to_molecular_analysis.xml"/>
<include file="db/changelog/migrations/57-Add_quality_control_table.xml"/>
</databaseChangeLog>
Loading

0 comments on commit e4796a3

Please sign in to comment.