Skip to content

Commit

Permalink
Edit templates for measurement registration (#832)
Browse files Browse the repository at this point in the history
* WIP

* wip

* make it work

* Extract behaviour

* remove unused method

* Adapt proteomics template

Fixes the edit case and renames instrument to MS device

fixes #786

* Make ngs row creation simpler

Uses the enum and enhanced switch to make sure all columns are covered and removes complexity.

* remove duplicate row creation for ngs

* Rename `Instrument` to `MS Device` in template

* Fix column name

* Fix sheet locking

Excel protected the visible sheet. I do not know why and can only speculate that some reordering was not complete. Creating the hidden sheet second solves the issue.

* replace instrument by ms device for proteomics

* correct spelling

* fix jpa access

* solves #747 add technical replicate

* fix constructors in tests

* use correct methods

* Fix wrong imports

Co-authored-by: steffengreiner <[email protected]>

* move test

Co-authored-by: steffengreiner <[email protected]>

* Add QBIC_SAMPLE_ID

Co-authored-by: steffengreiner <[email protected]>

---------

Co-authored-by: steffengreiner <[email protected]>
  • Loading branch information
KochTobi and Steffengreiner authored Sep 17, 2024
1 parent 1f7f71b commit f99ebc2
Show file tree
Hide file tree
Showing 17 changed files with 705 additions and 348 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ public static Specification<ProteomicsMeasurement> isOrganisationLabel(String fi
public static Specification<ProteomicsMeasurement> isOntologyTermName(String filter) {
return (root, query, builder) -> {
Expression<String> function = builder.function("JSON_EXTRACT", String.class,
root.get("instrument"),
root.get("msDevice"),
builder.literal("$.name"));
return builder.like(function,
"%" + filter + "%");
Expand All @@ -263,7 +263,7 @@ public static Specification<ProteomicsMeasurement> isOntologyTermLabel(String fi
return (root, query, builder) ->
{
Expression<String> function = builder.function("JSON_EXTRACT", String.class,
root.get("instrument"), builder.literal("$.label"));
root.get("msDevice"), builder.literal("$.label"));
return builder.like(function,
"%" + filter + "%");
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,15 +389,20 @@ private Map<ProteomicsMeasurement, Collection<SampleIdCodeEntry>> buildPxP(
throw new MeasurementRegistrationException(ErrorCode.UNKNOWN_ORGANISATION_ROR_ID);
}

var instrumentQuery = resolveOntologyCURI(firstMetadataEntry.instrumentCURI());
if (instrumentQuery.isEmpty()) {
var msDeviceQuery = resolveOntologyCURI(firstMetadataEntry.msDeviceCURIE());
if (msDeviceQuery.isEmpty()) {
throw new MeasurementRegistrationException(ErrorCode.UNKNOWN_ONTOLOGY_TERM);
}

var method = new ProteomicsMethodMetadata(instrumentQuery.get(), firstMetadataEntry.facility(),
firstMetadataEntry.digestionMethod(), firstMetadataEntry.digestionEnzyme(),
firstMetadataEntry.enrichmentMethod(), firstMetadataEntry.lcColumn(),
firstMetadataEntry.lcmsMethod(), readInjectionVolume(firstMetadataEntry.injectionVolume()),
var method = new ProteomicsMethodMetadata(msDeviceQuery.get(),
firstMetadataEntry.technicalReplicateName(),
firstMetadataEntry.facility(),
firstMetadataEntry.digestionMethod(),
firstMetadataEntry.digestionEnzyme(),
firstMetadataEntry.enrichmentMethod(),
firstMetadataEntry.lcColumn(),
firstMetadataEntry.lcmsMethod(),
readInjectionVolume(firstMetadataEntry.injectionVolume()),
firstMetadataEntry.labeling()
.labelType());

Expand Down Expand Up @@ -611,12 +616,13 @@ private List<Result<MeasurementId, ErrorCode>> updateAllPxP(
throw new MeasurementRegistrationException(ErrorCode.UNKNOWN_ORGANISATION_ROR_ID);
}

var instrumentQuery = resolveOntologyCURI(measurementMetadata.instrumentCURI());
if (instrumentQuery.isEmpty()) {
var msDeviceQuery = resolveOntologyCURI(measurementMetadata.msDeviceCURIE());
if (msDeviceQuery.isEmpty()) {
throw new MeasurementRegistrationException(ErrorCode.UNKNOWN_ONTOLOGY_TERM);
}

var method = new ProteomicsMethodMetadata(instrumentQuery.get(),
var method = new ProteomicsMethodMetadata(msDeviceQuery.get(),
measurementMetadata.technicalReplicateName(),
measurementMetadata.facility(),
measurementMetadata.digestionMethod(), measurementMetadata.digestionEnzyme(),
measurementMetadata.enrichmentMethod(), measurementMetadata.lcColumn(),
Expand All @@ -642,15 +648,20 @@ private List<Result<MeasurementId, ErrorCode>> updateAllPxP(
throw new MeasurementRegistrationException(ErrorCode.UNKNOWN_ORGANISATION_ROR_ID);
}

var instrumentQuery = resolveOntologyCURI(firstEntry.instrumentCURI());
if (instrumentQuery.isEmpty()) {
var msDeviceQuery = resolveOntologyCURI(firstEntry.msDeviceCURIE());
if (msDeviceQuery.isEmpty()) {
throw new MeasurementRegistrationException(ErrorCode.UNKNOWN_ONTOLOGY_TERM);
}

var method = new ProteomicsMethodMetadata(instrumentQuery.get(), firstEntry.facility(),
firstEntry.digestionMethod(), firstEntry.digestionEnzyme(),
firstEntry.enrichmentMethod(), firstEntry.lcColumn(),
firstEntry.lcmsMethod(), readInjectionVolume(firstEntry.injectionVolume()),
var method = new ProteomicsMethodMetadata(msDeviceQuery.get(),
firstEntry.technicalReplicateName(),
firstEntry.facility(),
firstEntry.digestionMethod(),
firstEntry.digestionEnzyme(),
firstEntry.enrichmentMethod(),
firstEntry.lcColumn(),
firstEntry.lcmsMethod(),
readInjectionVolume(firstEntry.injectionVolume()),
firstEntry.labeling()
.labelType());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,26 @@
*
* @since 1.0.0
*/
public record ProteomicsMeasurementMetadata(String measurementId,
SampleCode sampleCode,
String organisationId, String instrumentCURI,
String samplePoolGroup, String facility,
String fractionName,
String digestionEnzyme,
String digestionMethod, String enrichmentMethod,
String injectionVolume, String lcColumn,
String lcmsMethod, Labeling labeling,
String comment) implements MeasurementMetadata {
public record ProteomicsMeasurementMetadata(
String measurementId,
SampleCode sampleCode,
String technicalReplicateName,
String organisationId,
String msDeviceCURIE,
String samplePoolGroup,
String facility,
String fractionName,
String digestionEnzyme,
String digestionMethod,
String enrichmentMethod,
String injectionVolume,
String lcColumn,
String lcmsMethod,
Labeling labeling,
String comment
) implements MeasurementMetadata {


public static ProteomicsMeasurementMetadata copyWithNewProperties(SampleCode associatedSample,
Labeling labeling,
ProteomicsMeasurementMetadata metadata) {
return new ProteomicsMeasurementMetadata(metadata.measurementId(),
associatedSample,
metadata.organisationId(),
metadata.instrumentCURI(),
metadata.samplePoolGroup(),
metadata.facility(),
metadata.fractionName(),
metadata.digestionEnzyme(),
metadata.digestionMethod(),
metadata.enrichmentMethod(),
metadata.injectionVolume(),
metadata.lcColumn(),
metadata.lcmsMethod(),
labeling,
metadata.comment());
}

@Override
public Optional<String> assignedSamplePoolGroup() {
return Optional.ofNullable(samplePoolGroup.isBlank() ? null : samplePoolGroup);
Expand Down Expand Up @@ -72,4 +60,5 @@ public boolean equals(Object o) {
public int hashCode() {
return measurementId.hashCode();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public ValidationResult validate(ProteomicsMeasurementMetadata measurementMetada
return validationPolicy.validateSampleId(measurementMetadata.sampleCode())
.combine(validationPolicy.validateMandatoryDataProvided(measurementMetadata))
.combine(validationPolicy.validateOrganisation(measurementMetadata.organisationId())
.combine(validationPolicy.validateInstrument(measurementMetadata.instrumentCURI())));
.combine(validationPolicy.validateMsDevice(measurementMetadata.msDeviceCURIE())));
}

/**
Expand All @@ -121,17 +121,18 @@ public ValidationResult validateUpdate(ProteomicsMeasurementMetadata metadata,
.combine(validationPolicy.validateMeasurementCode(metadata.measurementIdentifier().orElse(""))
.combine(validationPolicy.validateMandatoryDataForUpdate(metadata))
.combine(validationPolicy.validateOrganisation(metadata.organisationId())
.combine(validationPolicy.validateInstrument(metadata.instrumentCURI())
.combine(validationPolicy.validateMsDevice(metadata.msDeviceCURIE())
.combine(
validationPolicy.validateDigestionMethod(metadata.digestionMethod())))));
}

public enum PROTEOMICS_PROPERTY {
QBIC_SAMPLE_ID("qbic sample id"),
SAMPLE_LABEL("sample name"),
TECHNICAL_REPLICATE_NAME("technical replicate"),
ORGANISATION_ID("organisation id"),
FACILITY("facility"),
INSTRUMENT("instrument"),
MS_DEVICE("ms device"),
SAMPLE_POOL_GROUP("sample pool group"),
CYCLE_FRACTION_NAME("cycle/fraction name"),
DIGESTION_METHOD("digestion method"),
Expand Down Expand Up @@ -180,6 +181,10 @@ public static boolean isDigestionMethod(String input) {
public String getName() {
return name;
}

public static List<String> getOptions() {
return Arrays.stream(values()).map(DigestionMethod::getName).toList();
}
}

private class ValidationPolicy {
Expand All @@ -188,7 +193,7 @@ private class ValidationPolicy {

private static final String UNKNOWN_ORGANISATION_ID_MESSAGE = "The organisation ID does not seem to be a ROR ID: \"%s\"";

private static final String UNKNOWN_INSTRUMENT_ID = "Unknown instrument id: \"%s\"";
private static final String UNKNOWN_MS_DEVICE_ID = "Unknown ms device id: \"%s\"";

private static final String UNKNOWN_DIGESTION_METHOD = "Unknown digestion method: \"%s\"";

Expand Down Expand Up @@ -242,13 +247,13 @@ ValidationResult validateMeasurementCode(String measurementCode) {
List.of("Measurement Code: Unknown measurement for id '%s'".formatted(measurementCode))));
}

ValidationResult validateInstrument(String instrument) {
var result = terminologyService.findByCurie(instrument);
ValidationResult validateMsDevice(String msDevice) {
var result = terminologyService.findByCurie(msDevice);
if (result.isPresent()) {
return ValidationResult.successful(1);
}
return ValidationResult.withFailures(1,
List.of(UNKNOWN_INSTRUMENT_ID.formatted(instrument)));
List.of(UNKNOWN_MS_DEVICE_ID.formatted(msDevice)));
}

ValidationResult validateDigestionMethod(String digestionMethod) {
Expand All @@ -273,9 +278,9 @@ ValidationResult validateMandatoryDataForUpdate(ProteomicsMeasurementMetadata me
} else {
validation = validation.combine(ValidationResult.successful(1));
}
if (metadata.instrumentCURI().isBlank()) {
if (metadata.msDeviceCURIE().isBlank()) {
validation = validation.combine(
ValidationResult.withFailures(1, List.of("Instrument: missing mandatory metadata")));
ValidationResult.withFailures(1, List.of("MS Device: missing mandatory metadata")));
} else {
validation = validation.combine(ValidationResult.successful(1));
}
Expand Down Expand Up @@ -323,10 +328,10 @@ ValidationResult validateMandatoryDataProvided(
} else {
validation = validation.combine(ValidationResult.successful(1));
}
if (metadata.instrumentCURI().isBlank()) {
if (metadata.msDeviceCURIE().isBlank()) {
validation = validation.combine(
ValidationResult.withFailures(1,
List.of("Instrument: missing mandatory metadata")));
List.of("MS Device: missing mandatory metadata")));
} else {
validation = validation.combine(ValidationResult.successful(1));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import life.qbic.domain.concepts.LocalDomainEventDispatcher;
import java.util.Set;
import life.qbic.domain.concepts.LocalDomainEventDispatcher;
import life.qbic.projectmanagement.domain.Organisation;
import life.qbic.projectmanagement.domain.model.OntologyTerm;
import life.qbic.projectmanagement.domain.model.measurement.event.MeasurementCreatedEvent;
Expand Down Expand Up @@ -93,7 +93,7 @@ private NGSMeasurement(MeasurementId measurementId, ProjectId projectId,
this.measurementId = measurementId;
this.projectId = requireNonNull(projectId, "projectId must not be null");
this.organisation = requireNonNull(organisation, "organisation must not be null");
this.instrument = requireNonNull(method.instrument(), "instrument must not be null");
this.instrument = requireNonNull(method.instrument(), "msDevice must not be null");
this.measurementCode = requireNonNull(measurementCode, "measurement code must not be null");
this.facility = requireNonNull(method.facility(), "facility must not be null");
this.sequencingReadType = requireNonNull(method.sequencingReadType(),
Expand Down Expand Up @@ -136,7 +136,7 @@ public static NGSMeasurement createWithPool(ProjectId projectId, String samplePo
throws IllegalArgumentException {
requireNonNull(measurementCode, "measurement Code must not be null");
requireNonNull(method, "method must not be null");
requireNonNull(method.instrument(), "instrument must not be null");
requireNonNull(method.instrument(), "msDevice must not be null");
if (samplePool.isBlank()) {
throw new IllegalArgumentException("Sample Pool: no value provided");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ public class ProteomicsMeasurement {
private MeasurementId measurementId;

@Column(name = "instrument", columnDefinition = "longtext CHECK (json_valid(`instrument`))")
private OntologyTerm instrument;
private OntologyTerm msDevice;

@Column(name = "technicalReplicateName")
private String technicalReplicateName;

@Column(name = "samplePool")
private String samplePool = "";
Expand Down Expand Up @@ -127,8 +130,8 @@ private static void evaluateMandatorySpecificMetadata(

private static void evaluateMandatoryMetadata(ProteomicsMethodMetadata method)
throws IllegalArgumentException {
if (method.instrument() == null) {
throw new IllegalArgumentException("Instrument: Missing metadata.");
if (method.msDevice() == null) {
throw new IllegalArgumentException("MS Device: Missing metadata.");
}
if (method.facility().isBlank()) {
throw new IllegalArgumentException("Facility: Missing metadata");
Expand Down Expand Up @@ -157,7 +160,7 @@ public static ProteomicsMeasurement create(ProjectId projectId,
MeasurementCode measurementCode, Organisation organisation, ProteomicsMethodMetadata method,
Collection<ProteomicsSpecificMeasurementMetadata> proteomicsSpecificMeasurementMetadata)
throws IllegalArgumentException {
requireNonNull(method.instrument());
requireNonNull(method.msDevice());
requireNonNull(measurementCode);
requireNonNull(proteomicsSpecificMeasurementMetadata);
if (!measurementCode.isMSDomain()) {
Expand Down Expand Up @@ -215,8 +218,8 @@ public Collection<SampleId> measuredSamples() {
.toList();
}

public OntologyTerm instrument() {
return instrument;
public OntologyTerm msDevice() {
return msDevice;
}

public Organisation organisation() {
Expand Down Expand Up @@ -257,7 +260,8 @@ public void updateMethod(ProteomicsMethodMetadata method) {
}

private void setMethodMetadata(ProteomicsMethodMetadata methodMetadata) {
this.instrument = methodMetadata.instrument();
this.msDevice = methodMetadata.msDevice();
this.technicalReplicateName = methodMetadata.technicalReplicate();
this.facility = methodMetadata.facility();
this.digestionMethod = methodMetadata.digestionMethod();
this.digestionEnzyme = methodMetadata.digestionEnzyme();
Expand Down Expand Up @@ -319,4 +323,8 @@ public int hashCode() {
public Optional<String> comment() {
return Optional.empty();
}

public Optional<String> technicalReplicateName() {
return Optional.ofNullable(technicalReplicateName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@
*
* @since 1.0.0
*/
public record ProteomicsMethodMetadata(OntologyTerm instrument, String facility,
String digestionMethod,
String digestionEnzyme, String enrichmentMethod,
String lcColumn, String lcmsMethod, int injectionVolume,
String labelType) {
public record ProteomicsMethodMetadata(
OntologyTerm msDevice,
String technicalReplicate,
String facility,
String digestionMethod,
String digestionEnzyme,
String enrichmentMethod,
String lcColumn,
String lcmsMethod,
int injectionVolume,
String labelType
) {

}
Loading

0 comments on commit f99ebc2

Please sign in to comment.