Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions resources/queries/targetedms/qcannotation/.qview.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<column name="Date" />
<column name="EndDate" />
<column name="QCAnnotationTypeId" />
<column name="instrumentModel" />
<column name="instrumentSerialNumber" />
<column name="Container" />
<column name="Created" />
<column name="Modified" />
Expand Down
1 change: 1 addition & 0 deletions resources/queries/targetedms/qcannotationtype/.qview.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<column name="Description" />
<column name="Color" />
<column name="Container" />
<column name="Shareable"/>
<column name="Created" />
<column name="Modified" />
</columns>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE targetedms.QCAnnotationType ADD COLUMN Shareable BOOLEAN DEFAULT FALSE;
ALTER TABLE targetedms.QCAnnotation ADD COLUMN instrumentModel VARCHAR(300);
ALTER TABLE targetedms.QCAnnotation ADD COLUMN instrumentSerialNumber VARCHAR(200);

UPDATE targetedms.QCAnnotationType SET Shareable = TRUE WHERE Name = 'Instrumentation Change';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
SELECT core.executeJavaUpgradeCode('reparentOrphanedTargetedMSData');

-- Adding missing foreign keys to core.Containers(EntityId)
ALTER TABLE targetedms.Runs ADD CONSTRAINT FK_Runs_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
ALTER TABLE targetedms.QCAnnotation ADD CONSTRAINT FK_QCAnnotation_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
ALTER TABLE targetedms.GuideSet ADD CONSTRAINT FK_GuideSet_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
ALTER TABLE targetedms.AutoQCPing ADD CONSTRAINT FK_AutoQCPing_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
ALTER TABLE targetedms.PrecursorChromInfo ADD CONSTRAINT FK_PrecursorChromInfo_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
ALTER TABLE targetedms.SampleFileChromInfo ADD CONSTRAINT FK_SampleFileChromInfo_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);

-- Adding missing indices on Container
CREATE INDEX IX_QCAnnotationType_Container ON targetedms.QCAnnotationType(Container);
CREATE INDEX IX_QCAnnotation_Container ON targetedms.QCAnnotation(Container);
CREATE INDEX IX_GuideSet_Container ON targetedms.GuideSet(Container);
CREATE INDEX IX_QCMetricConfiguration_Container ON targetedms.QCMetricConfiguration(Container);
3 changes: 3 additions & 0 deletions resources/schemas/targetedms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,7 @@
<column columnName="Name"/>
<column columnName="Description"/>
<column columnName="Color"/>
<column columnName="Shareable"/>
</columns>
</table>

Expand Down Expand Up @@ -1307,6 +1308,8 @@
<columnTitle>Annotation Type</columnTitle>
<description>The category of the event</description>
</column>
<column columnName="instrumentModel"/>
<column columnName="instrumentSerialNumber"/>
</columns>
</table>
<table tableName="QCMetricConfiguration" tableDbType="TABLE">
Expand Down
3 changes: 3 additions & 0 deletions src/org/labkey/targetedms/TargetedMSController.java
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,9 @@ else if (FolderType.QC.toString().equals(folderSetupForm.getFolderType()))
addDataPipelineTab(c);
addRawFilesPipelineTab(c);

// We may have toggled into or out of QC folder type, so clear out the cache
TargetedMSManager.get().clearQCMetricCache(c, true);

// Inform listeners so that any additional folder configuration can be done.
TargetedMSService.get().getTargetedMSFolderTypeListeners().forEach(listener -> listener.folderCreated(c, getUser()));

Expand Down
88 changes: 80 additions & 8 deletions src/org/labkey/targetedms/TargetedMSManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package org.labkey.targetedms;

import com.google.common.base.Joiner;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -165,9 +167,18 @@ private TargetedMSManager()
private static final Cache<Container, List<QCMetricConfiguration>> _metricCache = CacheManager.getBlockingCache(1000, TimeUnit.HOURS.toMillis(1), "Enabled QC metric configs",
(c, argument) ->
{
if (!(argument instanceof TargetedMSSchema schema))
{
throw new IllegalArgumentException("Argument must be a TargetedMSSchema but was " + argument);
}

if (getFolderType(schema.getContainer()) != TargetedMSService.FolderType.QC)
{
return Collections.emptyList();
}

try
{
TargetedMSSchema schema = (TargetedMSSchema) argument;
TableInfo metricsTable = schema.getTableOrThrow("qcMetricsConfig", null);
List<QCMetricConfiguration> metrics = new TableSelector(metricsTable, null, new Sort(FieldKey.fromParts("Name"))).getArrayList(QCMetricConfiguration.class);

Expand Down Expand Up @@ -207,7 +218,8 @@ public static TargetedMSManager get()

public static List<SampleFileChromInfo> getSampleFileChromInfos(SampleFile sampleFile)
{
return new TableSelector(getTableInfoSampleFileChromInfo(), new SimpleFilter(FieldKey.fromParts("SampleFileId"), sampleFile.getId()), new Sort("TextId")).getArrayList(SampleFileChromInfo.class); }
return new TableSelector(getTableInfoSampleFileChromInfo(), new SimpleFilter(FieldKey.fromParts("SampleFileId"), sampleFile.getId()), new Sort("TextId")).getArrayList(SampleFileChromInfo.class);
}

public static SampleFileChromInfo getSampleFileChromInfo(int id, Container c)
{
Expand Down Expand Up @@ -548,7 +560,8 @@ public static TableInfo getTableInfoQuantificationSettings()
return getSchema().getTable(TargetedMSSchema.TABLE_QUANTIIFICATION_SETTINGS);
}

public static TableInfo getTableInfoCalibrationCurve() {
public static TableInfo getTableInfoCalibrationCurve()
{
return getSchema().getTable(TargetedMSSchema.TABLE_CALIBRATION_CURVE);
}

Expand Down Expand Up @@ -628,19 +641,23 @@ public static TableInfo getTableInfoSkylineAuditLogMessage()
return getSchema().getTable(TargetedMSSchema.TABLE_SKYLINE_AUDITLOG_MESSAGE);
}

public static TableInfo getTableInfoListDefinition() {
public static TableInfo getTableInfoListDefinition()
{
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_DEFINITION);
}

public static TableInfo getTableInfoListColumnDefinition() {
public static TableInfo getTableInfoListColumnDefinition()
{
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_COLUMN_DEFINITION);
}

public static TableInfo getTableInfoListItem() {
public static TableInfo getTableInfoListItem()
{
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_ITEM);
}

public static TableInfo getTableInfoListItemValue() {
public static TableInfo getTableInfoListItemValue()
{
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_ITEM_VALUE);
}

Expand Down Expand Up @@ -1246,7 +1263,7 @@ public List<InstrumentNickname> getNickname(String name, TargetedMSSchema schema
}

List<InstrumentNickname> result = new ArrayList<>(dedupeAcrossContainers.values());

if (matches.isEmpty())
{
String sql = "SELECT DISTINCT InstrumentNickname, " +
Expand Down Expand Up @@ -2516,6 +2533,17 @@ public void moveRun(TargetedMSRun run, Container newContainer, String newRunLSID

new SqlExecutor(getSchema()).execute(updatePrecChromInfoSql);

SQLFragment updateSampleFileChromInfoSql = new SQLFragment("UPDATE ");
updateSampleFileChromInfoSql.append(getTableInfoSampleFileChromInfo(), "");
updateSampleFileChromInfoSql.append(" SET container = ?").add(newContainer);
updateSampleFileChromInfoSql.append(" WHERE sampleFileId IN (");
updateSampleFileChromInfoSql.append(" SELECT sf.Id FROM ").append(getTableInfoSampleFile(), "sf");
updateSampleFileChromInfoSql.append(" INNER JOIN ").append(getTableInfoReplicate(), "rep").append(" ON rep.Id = sf.ReplicateId");
updateSampleFileChromInfoSql.append(" WHERE rep.runId = ?").add(run.getId());
updateSampleFileChromInfoSql.append(" )");

new SqlExecutor(getSchema()).execute(updateSampleFileChromInfoSql);

run.setExperimentRunLSID(newRunLSID);
run.setDataId(newDataRowId);
run.setContainer(newContainer);
Expand Down Expand Up @@ -3046,6 +3074,39 @@ private QueryUpdateService getNicknameUpdateService(User user, Container contain
return Objects.requireNonNull(table.getUpdateService());
}

public static class InstrumentDetails
{
@Getter @Setter
private String instrumentSerialNumber;
@Getter @Setter
private String model;

public InstrumentDetails()
{
}
}

public static List<InstrumentDetails> getInstrumentDetails(Container container)
{
SQLFragment sql = new SQLFragment("SELECT DISTINCT sf.InstrumentSerialNumber, i.Model FROM ");
sql.append(getTableInfoSampleFile(), "sf");
sql.append(" INNER JOIN ");
sql.append(getTableInfoInstrument(), "i");
sql.append(" ON sf.InstrumentId = i.Id ");
sql.append(" INNER JOIN ");
sql.append(getTableInfoReplicate(), "rep");
sql.append(" ON sf.ReplicateId = rep.Id ");
sql.append(" INNER JOIN ");
sql.append(getTableInfoRuns(), "r");
sql.append(" ON rep.RunId = r.Id ");
sql.append(" WHERE r.Container = ?");
sql.add(container);

return new SqlSelector(getSchema(), sql).getArrayList(InstrumentDetails.class);

}


public void deleteNickname(InstrumentNickname name, User user) throws SQLException, BatchValidationException, QueryUpdateServiceException, InvalidKeyException
{
getNicknameUpdateService(user, name.getContainer()).
Expand All @@ -3071,4 +3132,15 @@ public void saveNickname(InstrumentNickname name, User user) throws SQLException
insertRows(user, name.getContainer(), Arrays.asList(row), errors, null, null);
}
}

public static boolean isQCAnnotationTypeShareable(int qcAnnotationTypeId)
{
SQLFragment sql = new SQLFragment("SELECT Shareable FROM ");
sql.append(getTableInfoQCAnnotationType());
sql.append(" WHERE Id = ?");
sql.add(qcAnnotationTypeId);

Boolean isShareable = new SqlSelector(getSchema(), sql).getObject(Boolean.class);
return isShareable != null && isShareable;
}
}
2 changes: 1 addition & 1 deletion src/org/labkey/targetedms/TargetedMSModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public String getName()
@Override
public Double getSchemaVersion()
{
return 26.002;
return 26.004;
}

@Override
Expand Down
38 changes: 38 additions & 0 deletions src/org/labkey/targetedms/TargetedMSUpgradeCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,42 @@ public void populatePTMPercentsGroupedPrepivotCache(final ModuleContext moduleCo

LOG.info("Finished populating PTMPercentsGroupedPrepivotCache for existing ExperimentMAM folders");
}

@SuppressWarnings("UnusedDeclaration")
public void reparentOrphanedTargetedMSData(final ModuleContext moduleContext)
{
if (moduleContext.isNewInstall())
{
return;
}

Container sharedContainer = ContainerManager.getSharedContainer();

SqlExecutor executor = new SqlExecutor(TargetedMSManager.getSchema());

String[] tablesToDeleteOrphans = {"QCAnnotation", "GuideSet", "AutoQCPing"};
for (String tableName : tablesToDeleteOrphans)
{
SQLFragment deleteSql = new SQLFragment("DELETE FROM targetedms.").append(tableName)
.append(" WHERE Container NOT IN (SELECT EntityId FROM core.Containers)");
int deletedCount = executor.execute(deleteSql);
if (deletedCount > 0)
{
LOG.info("Deleted " + deletedCount + " orphaned rows from targetedms." + tableName);
}
}

String[] tablesToReparentOrphans = {"Runs", "PrecursorChromInfo", "SampleFileChromInfo"};
for (String tableName : tablesToReparentOrphans)
{
SQLFragment updateSql = new SQLFragment("UPDATE targetedms.").append(tableName)
.append(" SET Container = ? WHERE Container NOT IN (SELECT EntityId FROM core.Containers)")
.add(sharedContainer.getEntityId());
int updatedCount = executor.execute(updateSql);
if (updatedCount > 0)
{
LOG.info("Reparented " + updatedCount + " orphaned rows from targetedms." + tableName + " to /Shared");
}
}
}
}
64 changes: 64 additions & 0 deletions src/org/labkey/targetedms/query/QCAnnotationTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,27 @@
*/
package org.labkey.targetedms.query;

import org.jetbrains.annotations.Nullable;
import org.labkey.api.data.Container;
import org.labkey.api.data.ContainerFilter;
import org.labkey.api.data.TableInfo;
import org.labkey.api.gwt.client.AuditBehaviorType;
import org.labkey.api.query.BatchValidationException;
import org.labkey.api.query.DefaultQueryUpdateService;
import org.labkey.api.query.DuplicateKeyException;
import org.labkey.api.query.QueryForeignKey;
import org.labkey.api.query.QueryUpdateService;
import org.labkey.api.query.QueryUpdateServiceException;
import org.labkey.api.query.SimpleUserSchema;
import org.labkey.api.query.ValidationException;
import org.labkey.api.security.User;
import org.labkey.targetedms.TargetedMSManager;
import org.labkey.targetedms.TargetedMSSchema;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import static org.labkey.targetedms.query.GuideSetTable.appendFormatLabel;

/**
Expand All @@ -44,4 +58,54 @@ public QCAnnotationTable(TargetedMSSchema schema, ContainerFilter cf)
appendFormatLabel(getMutableColumn("EndDate"));
setAuditBehavior(AuditBehaviorType.DETAILED);
}

@Override
public QueryUpdateService getUpdateService()
{
TableInfo table = getRealTable();
if (table != null)
{
return new DefaultQueryUpdateService(this, getRealTable())
{
@Override
public List<Map<String, Object>> insertRows(User user, Container container, List<Map<String, Object>> rows, BatchValidationException errors, @Nullable Map<Enum, Object> configParameters, @Nullable Map<String, Object> extraScriptContext) throws SQLException, QueryUpdateServiceException, DuplicateKeyException
{
List<Map<String, Object>> resultRows = new java.util.ArrayList<>();
for (Map<String, Object> row : rows)
{
// Check if the QCAnnotationType is shareable
int qcAnnotationTypeId = (Integer) row.get("QCAnnotationTypeId");
boolean isShareable = TargetedMSManager.isQCAnnotationTypeShareable(qcAnnotationTypeId);

if (isShareable)
{
List<TargetedMSManager.InstrumentDetails> instruments = TargetedMSManager.getInstrumentDetails(getContainer());
if (instruments.isEmpty())
{
resultRows.add(row);
}
else
{
for (TargetedMSManager.InstrumentDetails instrument : instruments)
{
Map<String, Object> newRow = new java.util.HashMap<>(row);
newRow.put("instrumentModel", instrument.getModel());
newRow.put("instrumentSerialNumber", instrument.getInstrumentSerialNumber());
newRow.put("Container", getContainer().getId());
resultRows.add(newRow);
}
}
}
else
{
resultRows.add(row);
}
}

return super.insertRows(user, container, resultRows, errors, configParameters, extraScriptContext);
}
};
}
return null;
}
}
Loading
Loading