Skip to content

Commit 0bb366b

Browse files
Merge 26.3 to develop
2 parents f9755d6 + ab6f251 commit 0bb366b

14 files changed

Lines changed: 600 additions & 82 deletions

File tree

resources/queries/targetedms/qcannotation/.qview.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<column name="Date" />
55
<column name="EndDate" />
66
<column name="QCAnnotationTypeId" />
7+
<column name="instrumentModel" />
8+
<column name="instrumentSerialNumber" />
79
<column name="Container" />
810
<column name="Created" />
911
<column name="Modified" />

resources/queries/targetedms/qcannotationtype/.qview.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<column name="Description" />
55
<column name="Color" />
66
<column name="Container" />
7+
<column name="Shareable"/>
78
<column name="Created" />
89
<column name="Modified" />
910
</columns>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ALTER TABLE targetedms.QCAnnotationType ADD COLUMN Shareable BOOLEAN DEFAULT FALSE;
2+
ALTER TABLE targetedms.QCAnnotation ADD COLUMN instrumentModel VARCHAR(300);
3+
ALTER TABLE targetedms.QCAnnotation ADD COLUMN instrumentSerialNumber VARCHAR(200);
4+
5+
UPDATE targetedms.QCAnnotationType SET Shareable = TRUE WHERE Name = 'Instrumentation Change';
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
SELECT core.executeJavaUpgradeCode('reparentOrphanedTargetedMSData');
2+
3+
-- Adding missing foreign keys to core.Containers(EntityId)
4+
ALTER TABLE targetedms.Runs ADD CONSTRAINT FK_Runs_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
5+
ALTER TABLE targetedms.QCAnnotation ADD CONSTRAINT FK_QCAnnotation_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
6+
ALTER TABLE targetedms.GuideSet ADD CONSTRAINT FK_GuideSet_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
7+
ALTER TABLE targetedms.AutoQCPing ADD CONSTRAINT FK_AutoQCPing_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
8+
ALTER TABLE targetedms.PrecursorChromInfo ADD CONSTRAINT FK_PrecursorChromInfo_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
9+
ALTER TABLE targetedms.SampleFileChromInfo ADD CONSTRAINT FK_SampleFileChromInfo_Container FOREIGN KEY (Container) REFERENCES core.Containers(EntityId);
10+
11+
-- Adding missing indices on Container
12+
CREATE INDEX IX_QCAnnotationType_Container ON targetedms.QCAnnotationType(Container);
13+
CREATE INDEX IX_QCAnnotation_Container ON targetedms.QCAnnotation(Container);
14+
CREATE INDEX IX_GuideSet_Container ON targetedms.GuideSet(Container);
15+
CREATE INDEX IX_QCMetricConfiguration_Container ON targetedms.QCMetricConfiguration(Container);

resources/schemas/targetedms.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,7 @@
12621262
<column columnName="Name"/>
12631263
<column columnName="Description"/>
12641264
<column columnName="Color"/>
1265+
<column columnName="Shareable"/>
12651266
</columns>
12661267
</table>
12671268

@@ -1307,6 +1308,8 @@
13071308
<columnTitle>Annotation Type</columnTitle>
13081309
<description>The category of the event</description>
13091310
</column>
1311+
<column columnName="instrumentModel"/>
1312+
<column columnName="instrumentSerialNumber"/>
13101313
</columns>
13111314
</table>
13121315
<table tableName="QCMetricConfiguration" tableDbType="TABLE">

src/org/labkey/targetedms/TargetedMSController.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,9 @@ else if (FolderType.QC.toString().equals(folderSetupForm.getFolderType()))
505505
addDataPipelineTab(c);
506506
addRawFilesPipelineTab(c);
507507

508+
// We may have toggled into or out of QC folder type, so clear out the cache
509+
TargetedMSManager.get().clearQCMetricCache(c, true);
510+
508511
// Inform listeners so that any additional folder configuration can be done.
509512
TargetedMSService.get().getTargetedMSFolderTypeListeners().forEach(listener -> listener.folderCreated(c, getUser()));
510513

src/org/labkey/targetedms/TargetedMSManager.java

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.labkey.targetedms;
1818

1919
import com.google.common.base.Joiner;
20+
import lombok.Getter;
21+
import lombok.Setter;
2022
import org.apache.commons.io.FilenameUtils;
2123
import org.apache.commons.lang3.StringUtils;
2224
import org.apache.logging.log4j.Logger;
@@ -165,9 +167,18 @@ private TargetedMSManager()
165167
private static final Cache<Container, List<QCMetricConfiguration>> _metricCache = CacheManager.getBlockingCache(1000, TimeUnit.HOURS.toMillis(1), "Enabled QC metric configs",
166168
(_, argument) ->
167169
{
170+
if (!(argument instanceof TargetedMSSchema schema))
171+
{
172+
throw new IllegalArgumentException("Argument must be a TargetedMSSchema but was " + argument);
173+
}
174+
175+
if (getFolderType(schema.getContainer()) != TargetedMSService.FolderType.QC)
176+
{
177+
return Collections.emptyList();
178+
}
179+
168180
try
169181
{
170-
TargetedMSSchema schema = (TargetedMSSchema) argument;
171182
TableInfo metricsTable = schema.getTableOrThrow("qcMetricsConfig", null);
172183
List<QCMetricConfiguration> metrics = new TableSelector(metricsTable, null, new Sort(FieldKey.fromParts("Name"))).getArrayList(QCMetricConfiguration.class);
173184

@@ -207,7 +218,8 @@ public static TargetedMSManager get()
207218

208219
public static List<SampleFileChromInfo> getSampleFileChromInfos(SampleFile sampleFile)
209220
{
210-
return new TableSelector(getTableInfoSampleFileChromInfo(), new SimpleFilter(FieldKey.fromParts("SampleFileId"), sampleFile.getId()), new Sort("TextId")).getArrayList(SampleFileChromInfo.class); }
221+
return new TableSelector(getTableInfoSampleFileChromInfo(), new SimpleFilter(FieldKey.fromParts("SampleFileId"), sampleFile.getId()), new Sort("TextId")).getArrayList(SampleFileChromInfo.class);
222+
}
211223

212224
public static SampleFileChromInfo getSampleFileChromInfo(int id, Container c)
213225
{
@@ -548,7 +560,8 @@ public static TableInfo getTableInfoQuantificationSettings()
548560
return getSchema().getTable(TargetedMSSchema.TABLE_QUANTIIFICATION_SETTINGS);
549561
}
550562

551-
public static TableInfo getTableInfoCalibrationCurve() {
563+
public static TableInfo getTableInfoCalibrationCurve()
564+
{
552565
return getSchema().getTable(TargetedMSSchema.TABLE_CALIBRATION_CURVE);
553566
}
554567

@@ -628,19 +641,23 @@ public static TableInfo getTableInfoSkylineAuditLogMessage()
628641
return getSchema().getTable(TargetedMSSchema.TABLE_SKYLINE_AUDITLOG_MESSAGE);
629642
}
630643

631-
public static TableInfo getTableInfoListDefinition() {
644+
public static TableInfo getTableInfoListDefinition()
645+
{
632646
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_DEFINITION);
633647
}
634648

635-
public static TableInfo getTableInfoListColumnDefinition() {
649+
public static TableInfo getTableInfoListColumnDefinition()
650+
{
636651
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_COLUMN_DEFINITION);
637652
}
638653

639-
public static TableInfo getTableInfoListItem() {
654+
public static TableInfo getTableInfoListItem()
655+
{
640656
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_ITEM);
641657
}
642658

643-
public static TableInfo getTableInfoListItemValue() {
659+
public static TableInfo getTableInfoListItemValue()
660+
{
644661
return getSchema().getTable(TargetedMSSchema.TABLE_LIST_ITEM_VALUE);
645662
}
646663

@@ -1246,7 +1263,7 @@ public List<InstrumentNickname> getNickname(String name, TargetedMSSchema schema
12461263
}
12471264

12481265
List<InstrumentNickname> result = new ArrayList<>(dedupeAcrossContainers.values());
1249-
1266+
12501267
if (matches.isEmpty())
12511268
{
12521269
String sql = "SELECT DISTINCT InstrumentNickname, " +
@@ -2516,6 +2533,17 @@ public void moveRun(TargetedMSRun run, Container newContainer, String newRunLSID
25162533

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

2536+
SQLFragment updateSampleFileChromInfoSql = new SQLFragment("UPDATE ");
2537+
updateSampleFileChromInfoSql.append(getTableInfoSampleFileChromInfo(), "");
2538+
updateSampleFileChromInfoSql.append(" SET container = ?").add(newContainer);
2539+
updateSampleFileChromInfoSql.append(" WHERE sampleFileId IN (");
2540+
updateSampleFileChromInfoSql.append(" SELECT sf.Id FROM ").append(getTableInfoSampleFile(), "sf");
2541+
updateSampleFileChromInfoSql.append(" INNER JOIN ").append(getTableInfoReplicate(), "rep").append(" ON rep.Id = sf.ReplicateId");
2542+
updateSampleFileChromInfoSql.append(" WHERE rep.runId = ?").add(run.getId());
2543+
updateSampleFileChromInfoSql.append(" )");
2544+
2545+
new SqlExecutor(getSchema()).execute(updateSampleFileChromInfoSql);
2546+
25192547
run.setExperimentRunLSID(newRunLSID);
25202548
run.setDataId(newDataRowId);
25212549
run.setContainer(newContainer);
@@ -3047,6 +3075,39 @@ private QueryUpdateService getNicknameUpdateService(User user, Container contain
30473075
return Objects.requireNonNull(table.getUpdateService());
30483076
}
30493077

3078+
public static class InstrumentDetails
3079+
{
3080+
@Getter @Setter
3081+
private String instrumentSerialNumber;
3082+
@Getter @Setter
3083+
private String model;
3084+
3085+
public InstrumentDetails()
3086+
{
3087+
}
3088+
}
3089+
3090+
public static List<InstrumentDetails> getInstrumentDetails(Container container)
3091+
{
3092+
SQLFragment sql = new SQLFragment("SELECT DISTINCT sf.InstrumentSerialNumber, i.Model FROM ");
3093+
sql.append(getTableInfoSampleFile(), "sf");
3094+
sql.append(" INNER JOIN ");
3095+
sql.append(getTableInfoInstrument(), "i");
3096+
sql.append(" ON sf.InstrumentId = i.Id ");
3097+
sql.append(" INNER JOIN ");
3098+
sql.append(getTableInfoReplicate(), "rep");
3099+
sql.append(" ON sf.ReplicateId = rep.Id ");
3100+
sql.append(" INNER JOIN ");
3101+
sql.append(getTableInfoRuns(), "r");
3102+
sql.append(" ON rep.RunId = r.Id ");
3103+
sql.append(" WHERE r.Container = ?");
3104+
sql.add(container);
3105+
3106+
return new SqlSelector(getSchema(), sql).getArrayList(InstrumentDetails.class);
3107+
3108+
}
3109+
3110+
30503111
public void deleteNickname(InstrumentNickname name, User user) throws SQLException, BatchValidationException, QueryUpdateServiceException, InvalidKeyException
30513112
{
30523113
getNicknameUpdateService(user, name.getContainer()).
@@ -3072,4 +3133,15 @@ public void saveNickname(InstrumentNickname name, User user) throws SQLException
30723133
insertRows(user, name.getContainer(), Arrays.asList(row), errors, null, null);
30733134
}
30743135
}
3136+
3137+
public static boolean isQCAnnotationTypeShareable(int qcAnnotationTypeId)
3138+
{
3139+
SQLFragment sql = new SQLFragment("SELECT Shareable FROM ");
3140+
sql.append(getTableInfoQCAnnotationType());
3141+
sql.append(" WHERE Id = ?");
3142+
sql.add(qcAnnotationTypeId);
3143+
3144+
Boolean isShareable = new SqlSelector(getSchema(), sql).getObject(Boolean.class);
3145+
return isShareable != null && isShareable;
3146+
}
30753147
}

src/org/labkey/targetedms/TargetedMSModule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ public String getName()
231231
@Override
232232
public Double getSchemaVersion()
233233
{
234-
return 26.002;
234+
return 26.004;
235235
}
236236

237237
@Override

src/org/labkey/targetedms/TargetedMSUpgradeCode.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,42 @@ public void populatePTMPercentsGroupedPrepivotCache(final ModuleContext moduleCo
108108

109109
LOG.info("Finished populating PTMPercentsGroupedPrepivotCache for existing ExperimentMAM folders");
110110
}
111+
112+
@SuppressWarnings("UnusedDeclaration")
113+
public void reparentOrphanedTargetedMSData(final ModuleContext moduleContext)
114+
{
115+
if (moduleContext.isNewInstall())
116+
{
117+
return;
118+
}
119+
120+
Container sharedContainer = ContainerManager.getSharedContainer();
121+
122+
SqlExecutor executor = new SqlExecutor(TargetedMSManager.getSchema());
123+
124+
String[] tablesToDeleteOrphans = {"QCAnnotation", "GuideSet", "AutoQCPing"};
125+
for (String tableName : tablesToDeleteOrphans)
126+
{
127+
SQLFragment deleteSql = new SQLFragment("DELETE FROM targetedms.").append(tableName)
128+
.append(" WHERE Container NOT IN (SELECT EntityId FROM core.Containers)");
129+
int deletedCount = executor.execute(deleteSql);
130+
if (deletedCount > 0)
131+
{
132+
LOG.info("Deleted " + deletedCount + " orphaned rows from targetedms." + tableName);
133+
}
134+
}
135+
136+
String[] tablesToReparentOrphans = {"Runs", "PrecursorChromInfo", "SampleFileChromInfo"};
137+
for (String tableName : tablesToReparentOrphans)
138+
{
139+
SQLFragment updateSql = new SQLFragment("UPDATE targetedms.").append(tableName)
140+
.append(" SET Container = ? WHERE Container NOT IN (SELECT EntityId FROM core.Containers)")
141+
.add(sharedContainer.getEntityId());
142+
int updatedCount = executor.execute(updateSql);
143+
if (updatedCount > 0)
144+
{
145+
LOG.info("Reparented " + updatedCount + " orphaned rows from targetedms." + tableName + " to /Shared");
146+
}
147+
}
148+
}
111149
}

src/org/labkey/targetedms/query/QCAnnotationTable.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,27 @@
1515
*/
1616
package org.labkey.targetedms.query;
1717

18+
import org.jetbrains.annotations.Nullable;
19+
import org.labkey.api.data.Container;
1820
import org.labkey.api.data.ContainerFilter;
21+
import org.labkey.api.data.TableInfo;
1922
import org.labkey.api.gwt.client.AuditBehaviorType;
23+
import org.labkey.api.query.BatchValidationException;
24+
import org.labkey.api.query.DefaultQueryUpdateService;
25+
import org.labkey.api.query.DuplicateKeyException;
2026
import org.labkey.api.query.QueryForeignKey;
27+
import org.labkey.api.query.QueryUpdateService;
28+
import org.labkey.api.query.QueryUpdateServiceException;
2129
import org.labkey.api.query.SimpleUserSchema;
30+
import org.labkey.api.query.ValidationException;
31+
import org.labkey.api.security.User;
2232
import org.labkey.targetedms.TargetedMSManager;
2333
import org.labkey.targetedms.TargetedMSSchema;
2434

35+
import java.sql.SQLException;
36+
import java.util.List;
37+
import java.util.Map;
38+
2539
import static org.labkey.targetedms.query.GuideSetTable.appendFormatLabel;
2640

2741
/**
@@ -44,4 +58,54 @@ public QCAnnotationTable(TargetedMSSchema schema, ContainerFilter cf)
4458
appendFormatLabel(getMutableColumn("EndDate"));
4559
setAuditBehavior(AuditBehaviorType.DETAILED);
4660
}
61+
62+
@Override
63+
public QueryUpdateService getUpdateService()
64+
{
65+
TableInfo table = getRealTable();
66+
if (table != null)
67+
{
68+
return new DefaultQueryUpdateService(this, getRealTable())
69+
{
70+
@Override
71+
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
72+
{
73+
List<Map<String, Object>> resultRows = new java.util.ArrayList<>();
74+
for (Map<String, Object> row : rows)
75+
{
76+
// Check if the QCAnnotationType is shareable
77+
int qcAnnotationTypeId = (Integer) row.get("QCAnnotationTypeId");
78+
boolean isShareable = TargetedMSManager.isQCAnnotationTypeShareable(qcAnnotationTypeId);
79+
80+
if (isShareable)
81+
{
82+
List<TargetedMSManager.InstrumentDetails> instruments = TargetedMSManager.getInstrumentDetails(getContainer());
83+
if (instruments.isEmpty())
84+
{
85+
resultRows.add(row);
86+
}
87+
else
88+
{
89+
for (TargetedMSManager.InstrumentDetails instrument : instruments)
90+
{
91+
Map<String, Object> newRow = new java.util.HashMap<>(row);
92+
newRow.put("instrumentModel", instrument.getModel());
93+
newRow.put("instrumentSerialNumber", instrument.getInstrumentSerialNumber());
94+
newRow.put("Container", getContainer().getId());
95+
resultRows.add(newRow);
96+
}
97+
}
98+
}
99+
else
100+
{
101+
resultRows.add(row);
102+
}
103+
}
104+
105+
return super.insertRows(user, container, resultRows, errors, configParameters, extraScriptContext);
106+
}
107+
};
108+
}
109+
return null;
110+
}
47111
}

0 commit comments

Comments
 (0)