diff --git a/mcc/resources/etls/mcc.xml b/mcc/resources/etls/mcc.xml
index e5a788736..3dd604ab7 100644
--- a/mcc/resources/etls/mcc.xml
+++ b/mcc/resources/etls/mcc.xml
@@ -33,6 +33,7 @@
usage_future
date_of_observations
colony
+ source
dam
sire
objectid
diff --git a/mcc/resources/queries/study/demographicsLittermates.sql b/mcc/resources/queries/study/demographicsLittermates.sql
index d2edb072b..340fe7d3f 100644
--- a/mcc/resources/queries/study/demographicsLittermates.sql
+++ b/mcc/resources/queries/study/demographicsLittermates.sql
@@ -3,8 +3,8 @@ SELECT
d1.Id,
d1.litterId,
- (SELECT GROUP_CONCAT(distinct d2.Id, ',') as litterMates FROM study.Demographics d2 WHERE d2.qcstate.publicdata = true AND d1.litterId = d2.litterId AND d1.id != d2.id) as litterMates
+ (SELECT GROUP_CONCAT(distinct d2.Id, ',') as litterMates FROM study.Demographics d2 WHERE d2.qcstate.publicdata = true AND d2.litterId IS NOT NULL AND d1.litterId = d2.litterId AND d1.id != d2.id) as litterMates
FROM study.Demographics d1
-WHERE d1.qcstate.publicdata = true
+WHERE d1.qcstate.publicdata = true AND d1.litterId IS NOT NULL
diff --git a/mcc/resources/queries/study/demographicsMccTransfer.query.xml b/mcc/resources/queries/study/demographicsMccTransfer.query.xml
new file mode 100644
index 000000000..12904afb7
--- /dev/null
+++ b/mcc/resources/queries/study/demographicsMccTransfer.query.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ MCC Transfers
+ Summary of MCC Transfers
+
+
+ true
+ true
+
+
+ MCC Request ID
+
+
+ PI Last Name
+
+
+ PI First Name
+
+
+ PI Institution
+
+
+ mccRequestId
+
+
+
+
diff --git a/mcc/resources/queries/study/demographicsMccTransfer.sql b/mcc/resources/queries/study/demographicsMccTransfer.sql
new file mode 100644
index 000000000..99e1776b6
--- /dev/null
+++ b/mcc/resources/queries/study/demographicsMccTransfer.sql
@@ -0,0 +1,9 @@
+SELECT
+ d.Id,
+ GROUP_CONCAT(DISTINCT d.mccRequestId.rowId, ', ') as mccRequestId,
+ GROUP_CONCAT(DISTINCT d.mccRequestId.lastName, char(10)) as piLastName,
+ GROUP_CONCAT(DISTINCT d.mccRequestId.firstName, char(10)) as piFirstName,
+ GROUP_CONCAT(DISTINCT d.mccRequestId.institutionname, char(10)) as piInstitution
+FROM study.departure d
+WHERE d.qcstate.publicdata = true AND d.mccRequestId IS NOT NULL
+GROUP BY d.Id
\ No newline at end of file
diff --git a/mcc/src/org/labkey/mcc/etl/ProjectAssignmentTransform.java b/mcc/src/org/labkey/mcc/etl/ProjectAssignmentTransform.java
index d9cd9a044..a0c73faec 100644
--- a/mcc/src/org/labkey/mcc/etl/ProjectAssignmentTransform.java
+++ b/mcc/src/org/labkey/mcc/etl/ProjectAssignmentTransform.java
@@ -28,6 +28,7 @@ public class ProjectAssignmentTransform extends ColumnTransform
private static final String U24_BREEDER = "U24 breeder";
private static final String U24_OFFSPRING = "U24 offspring";
private static final String U24_OTHER = "Other";
+ private static final String U24_INACTIVE = "U24 marmoset breeding- INACTIVE -";
@Override
protected Object doTransform(Object inputValue)
@@ -42,6 +43,10 @@ protected Object doTransform(Object inputValue)
{
return getOrCreateFlag(U24_TITLE);
}
+ else if (U24_INACTIVE.equalsIgnoreCase(String.valueOf(inputValue)))
+ {
+ return getOrCreateFlag(U24_INACTIVE);
+ }
// SNPRC:
else if (U24_BREEDER.equalsIgnoreCase(String.valueOf(inputValue)))
{
@@ -51,8 +56,11 @@ else if (U24_OFFSPRING.equalsIgnoreCase(String.valueOf(inputValue)))
{
return getOrCreateFlag(U24_OFFSPRING);
}
-
- return inputValue;
+ else
+ {
+ _log.error("Unknown flag value: " + inputValue + ", in folder: " + getContainerUser().getContainer().getPath());
+ return null;
+ }
}
private String getOrCreateFlag(String type)
diff --git a/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java b/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java
index e917e4ac7..f042eb904 100644
--- a/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java
+++ b/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java
@@ -16,10 +16,11 @@
import org.labkey.api.query.FieldKey;
import org.labkey.api.query.LookupForeignKey;
import org.labkey.api.query.QueryForeignKey;
-import org.labkey.api.query.QueryService;
import org.labkey.api.query.UserSchema;
+import org.labkey.api.security.User;
import org.labkey.mcc.MccManager;
import org.labkey.mcc.MccSchema;
+import org.labkey.mcc.security.MccRequestAdminPermission;
public class MccEhrCustomizer extends AbstractTableCustomizer
{
@@ -141,6 +142,39 @@ private void customizeAnimalTable(AbstractTableInfo ti)
col.setDescription("Summary of genomic data");
ti.addColumn(col);
}
+
+ // Only allow this for authorized users:
+ possiblyAddRequestSummary(ti);
+ }
+
+ private void possiblyAddRequestSummary(AbstractTableInfo ti)
+ {
+ if (ti.getColumn("mccTransfers") != null)
+ {
+ return;
+ }
+
+ Container animalDataContainer = MccManager.get().getMCCContainer(ti.getUserSchema().getContainer());
+ if (animalDataContainer == null)
+ {
+ return;
+ }
+
+ if (!animalDataContainer.equals(ti.getUserSchema().getContainer()))
+ {
+ return;
+ }
+
+ User u = ti.getUserSchema().getUser();
+ if (!animalDataContainer.hasPermission(u, MccRequestAdminPermission.class))
+ {
+ return;
+ }
+
+ var col = getWrappedIdCol(ti.getUserSchema(), ti, "mccTransfers", "demographicsMccTransfer");
+ col.setLabel("MCC Transfers");
+ col.setDescription("Summarizes MCC Transfer Information");
+ ti.addColumn(col);
}
private BaseColumnInfo getWrappedIdCol(UserSchema us, AbstractTableInfo ds, String name, String queryName)
diff --git a/tcrdb/build.gradle b/tcrdb/build.gradle
index f22702e73..643cccb99 100644
--- a/tcrdb/build.gradle
+++ b/tcrdb/build.gradle
@@ -5,38 +5,12 @@ repositories {
mavenCentral()
}
-configurations.all {
- resolutionStrategy {
- // Related to: https://nvd.nist.gov/vuln/detail/CVE-2025-12183
- dependencySubstitution {
- substitute module('org.lz4:lz4-java') using module("at.yawk.lz4:lz4-java:${lz4Version}")
- }
- }
-}
-
dependencies {
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:DiscvrLabKeyModules:singlecell", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:DiscvrLabKeyModules:SequenceAnalysis", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:LabDevKitModules:laboratory", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:LabDevKitModules:LDK", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: BuildUtils.getPlatformModuleProjectPath(project.gradle, "assay"), depProjectConfig: "apiJarFile")
- BuildUtils.addExternalDependency(
- project,
- new ExternalDependency(
- "io.repseq:repseqio:${repseqVersion}",
- "repseqio",
- "repseqio",
- "https://github.com/repseqio/repseqio",
- ExternalDependency.APACHE_2_LICENSE_NAME,
- ExternalDependency.APACHE_2_LICENSE_URL,
- "TCR Analysis"
- ),
- {
- // exclude logback to prevent excessive logging
- exclude group: "ch.qos.logback", module :"logback-classic"
- exclude group: "ch.qos.logback", module :"logback-core"
- }
- )
implementation "com.github.samtools:htsjdk:${htsjdkVersion}"
implementation "net.sf.opencsv:opencsv:${opencsvVersion}"
diff --git a/tcrdb/gradle.properties b/tcrdb/gradle.properties
index 0e8bb0888..e69de29bb 100644
--- a/tcrdb/gradle.properties
+++ b/tcrdb/gradle.properties
@@ -1,2 +0,0 @@
-lz4Version=1.10.1
-repseqVersion=1.7.0
\ No newline at end of file
diff --git a/tcrdb/resources/assay/TCRdb/queries/Data.query.xml b/tcrdb/resources/assay/TCRdb/queries/Data.query.xml
index 20a2fb77e..df07a7e19 100644
--- a/tcrdb/resources/assay/TCRdb/queries/Data.query.xml
+++ b/tcrdb/resources/assay/TCRdb/queries/Data.query.xml
@@ -142,9 +142,6 @@
-
TCRdb.window.ExportDataWindow.viewAlignmentHandler(dataRegionName, arguments[0] ? arguments[0].ownerCt : null);
- -
- TCRdb.window.DownloadCloneWindow.buttonHandler(dataRegionName);
-
-
TCRdb.window.DownloadCloneWindow.downloadSequenceHandler(dataRegionName);
diff --git a/tcrdb/resources/web/tcrdb/window/DownloadCloneWindow.js b/tcrdb/resources/web/tcrdb/window/DownloadCloneWindow.js
index f4a1fa3ba..cb5c356e6 100644
--- a/tcrdb/resources/web/tcrdb/window/DownloadCloneWindow.js
+++ b/tcrdb/resources/web/tcrdb/window/DownloadCloneWindow.js
@@ -2,10 +2,6 @@ Ext4.define('TCRdb.window.DownloadCloneWindow', {
extend: 'Ext.window.Window',
statics: {
- buttonHandler: function(dataRegionName) {
- TCRdb.window.DownloadCloneWindow.showWindow(dataRegionName, 'downloadCloneMaterials', 'The goal of this is to download a ZIP with any extracted clone/read data for the selected sample(s), along with the reference sequence for the segments used. These files can be imported into Geneious or a similar program to de novo assemble to construct the FL clone. Note: per sample, it will export all reads overlapping any TCR segments. This at minimum will tend to include both chains (i.e. 2 different CDR3s), and might include reads that either match a defunct TCR or other noise.');
- },
-
downloadSequenceHandler: function(dataRegionName){
TCRdb.window.DownloadCloneWindow.showWindow(dataRegionName, 'downloadSequence', 'This will download the full sequence (if available) for the selected rows, along with the reference segments.');
},
diff --git a/tcrdb/src/org/labkey/tcrdb/TCRdbController.java b/tcrdb/src/org/labkey/tcrdb/TCRdbController.java
index f9c46e2ae..d73939f01 100644
--- a/tcrdb/src/org/labkey/tcrdb/TCRdbController.java
+++ b/tcrdb/src/org/labkey/tcrdb/TCRdbController.java
@@ -16,78 +16,43 @@
package org.labkey.tcrdb;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
+import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import org.jetbrains.annotations.NotNull;
-import org.labkey.api.action.ConfirmAction;
import org.labkey.api.action.ExportAction;
-import org.labkey.api.action.SimpleViewAction;
import org.labkey.api.action.SpringActionController;
import org.labkey.api.collections.IntHashMap;
-import org.labkey.api.collections.IntHashSet;
-import org.labkey.api.collections.StringHashMap;
import org.labkey.api.data.ColumnInfo;
import org.labkey.api.data.CompareType;
import org.labkey.api.data.Container;
import org.labkey.api.data.SimpleFilter;
import org.labkey.api.data.TableInfo;
import org.labkey.api.data.TableSelector;
-import org.labkey.api.exp.api.ExpData;
-import org.labkey.api.exp.api.ExperimentService;
-import org.labkey.api.pipeline.PipelineJobException;
import org.labkey.api.query.FieldKey;
-import org.labkey.api.query.QueryAction;
import org.labkey.api.query.QueryService;
import org.labkey.api.query.UserSchema;
-import org.labkey.api.reader.Readers;
import org.labkey.api.security.IgnoresTermsOfUse;
import org.labkey.api.security.RequiresPermission;
-import org.labkey.api.security.permissions.AdminPermission;
import org.labkey.api.security.permissions.ReadPermission;
import org.labkey.api.sequenceanalysis.RefNtSequenceModel;
-import org.labkey.api.sequenceanalysis.SequenceAnalysisService;
-import org.labkey.api.util.FileType;
-import org.labkey.api.util.FileUtil;
-import org.labkey.api.util.HtmlString;
import org.labkey.api.util.PageFlowUtil;
import org.labkey.api.util.StringUtilsLabKey;
-import org.labkey.api.util.URLHelper;
-import org.labkey.api.view.HtmlView;
-import org.labkey.api.view.NavTree;
-import org.labkey.api.view.SpringErrorView;
-import org.labkey.tcrdb.pipeline.MiXCRWrapper;
import org.springframework.validation.BindException;
-import org.springframework.validation.Errors;
-import org.springframework.web.servlet.ModelAndView;
-import jakarta.servlet.http.HttpServletResponse;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.StringWriter;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
public class TCRdbController extends SpringActionController
{
private static final DefaultActionResolver _actionResolver = new DefaultActionResolver(TCRdbController.class);
public static final String NAME = "tcrdb";
- private static final FileType FASTA = new FileType("fasta");
-
private static final Logger _log = LogManager.getLogger(TCRdbController.class);
public TCRdbController()
@@ -95,195 +60,6 @@ public TCRdbController()
setActionResolver(_actionResolver);
}
- //TODO: based on set of IDs, run exportAlignmentsPretty
-
- @RequiresPermission(ReadPermission.class)
- public class ExportAlignmentsAction extends SimpleViewAction
- {
- @Override
- public ModelAndView getView(ExportAlignmentsForm form, BindException errors) throws Exception
- {
- if (form.getAssayRowIds() == null || form.getAssayRowIds().length == 0)
- {
- errors.reject(ERROR_MSG, "Must provide IDs to display");
- return new SpringErrorView(errors);
- }
-
- if (StringUtils.isEmpty(form.getSchemaName()))
- {
- errors.reject(ERROR_MSG, "Must provide the assay schema name");
- return new SpringErrorView(errors);
- }
-
- //find rows
- UserSchema us = QueryService.get().getUserSchema(getUser(), getContainer(), form.getSchemaName());
- if (us == null)
- {
- errors.reject(ERROR_MSG, "Unknown schema: " + form.getSchemaName());
- return new SpringErrorView(errors);
- }
-
- TableInfo ti = us.getTable("data");
- final Map> VDJMap = new HashMap<>();
- List rowIds = new ArrayList<>(Arrays.asList(form.getAssayRowIds()));
-
- TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowid"), rowIds, CompareType.IN), null);
- final StringWriter writer = new StringWriter();
-
- ts.forEach(AssayRecord.class, r -> {
- if (r.getVdjFile() == null)
- {
- writer.write("ERROR: Row lacks VDJCA file: " + r.getRowId() + "\n");
- return;
- }
-
- ExpData d = ExperimentService.get().getExpData(r.getVdjFile());
- if (d == null)
- {
- writer.write("ERROR: Unable to find VDJCA file for row: " + r.getRowId() + ", ExpData: " + PageFlowUtil.filter(r.getVdjFile()) + "\n");
- return;
- }
-
- if (!d.getFile().exists())
- {
- writer.write("ERROR: Unable to find VDJCA file for row: " + r.getRowId() + ", file does not exist: " + PageFlowUtil.filter(d.getFile().getPath()) + "\n");
- return;
- }
-
- if (!VDJMap.containsKey(d.getFile()))
- {
- VDJMap.put(d.getFile(), new ArrayList<>());
- }
-
- VDJMap.get(d.getFile()).add(r);
- });
-
- if (VDJMap.isEmpty())
- {
- errors.reject(ERROR_MSG, "No matching rows found for IDs: " + StringUtils.join(rowIds, ","));
- return new SpringErrorView(errors);
- }
-
- SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
- for (File f : VDJMap.keySet())
- {
- File tmp = FileUtil.createTempFile("mixcr", ".txt");
- MiXCRWrapper wrapper = new MiXCRWrapper(_log);
- //TODO:
- //wrapper.setLibraryPath();
- List args = new ArrayList<>();
- if (StringUtils.trimToNull(form.getCdr3Equals()) != null)
- {
- args.add("--cdr3-equals");
- args.add(form.getCdr3Equals());
- }
-
- if (StringUtils.trimToNull(form.getReadContains()) != null)
- {
- args.add("--read-contains");
- args.add(form.getReadContains());
- }
-
- try
- {
- wrapper.doExportAlignmentsPretty(f, tmp, args);
-
- writer.write("File: " + PageFlowUtil.filter(f.getName()) + '\n');
- writer.write("Result Rows From This File: " + '\n');
- for (AssayRecord r : VDJMap.get(f))
- {
- writer.write("Sample: " + PageFlowUtil.filter(r.getSampleName()) + '\n');
- writer.write("Sample Date: " + PageFlowUtil.filter(r.getDate() == null ? "" : fmt.format(r.getDate())) + '\n');
- writer.write("CDR3: " + PageFlowUtil.filter(coalesce(r.getCDR3())) + '\n');
- writer.write("vHit: " + PageFlowUtil.filter(coalesce(r.getvHit())) + '\n');
- writer.write("dHit: " + PageFlowUtil.filter(coalesce(r.getdHit())) + '\n');
- writer.write("jHit: " + PageFlowUtil.filter(coalesce(r.getjHit())) + '\n');
- writer.write("cHit: " + PageFlowUtil.filter(coalesce(r.getcHit())) + '\n');
- writer.write("Read Count: " + PageFlowUtil.filter(coalesce(r.getCount())) + '\n');
- writer.write("Fraction: " + PageFlowUtil.filter(coalesce(r.getFraction())) + '\n');
- writer.write("Comments: " + PageFlowUtil.filter(coalesce(r.getComment())) + '\n');
- writer.write('\n');
- }
- writer.write('\n');
- try (BufferedReader reader = Readers.getReader(new FileInputStream(tmp)))
- {
- String line;
- boolean inAlignmentBlock = false;
- while ((line = reader.readLine()) != null)
- {
- line = PageFlowUtil.filter(line);
-
- String trimmed = StringUtils.trimToEmpty(line);
- if (StringUtils.isEmpty(trimmed))
- {
- inAlignmentBlock = false;
- }
-
- //Highlight mismatches
- if (inAlignmentBlock)
- {
- String[] tokens = trimmed.split("( )+");
- String alignmentRaw = tokens[2];
- StringBuilder sb = new StringBuilder();
- for (int i=0; i");
- sb.append(c);
- sb.append("");
- }
- else
- {
- sb.append(PageFlowUtil.filter(c));
- }
- }
-
- line = line.replaceAll(alignmentRaw, sb.toString());
- }
-
- writer.write(line + '\n');
-
- if (trimmed.startsWith("Target"))
- {
- inAlignmentBlock = true;
- }
- }
- }
-
- writer.write('\n');
- writer.write("
");
- writer.write('\n');
- writer.write('\n');
-
- tmp.delete();
- }
- catch (PipelineJobException e){
- writer.write("Unable to run export alignments\n");
-
- _log.error("Unable to run exportAlignments:\n" + StringUtils.join(wrapper.getCommandsExecuted(), "\n"), e);
- }
- }
-
- //mixcr exportReadsForClones index_file alignments.vdjca.gz 0 1 2 33 54 reads.fastq.gz
- //mixcr exportAlignmentsPretty input.vdjca test.txt
-
- return new HtmlView("MiXCR Alignments", HtmlString.unsafe(""));
- }
-
- private String coalesce(Object s)
- {
- return s == null ? "None" : s.toString();
- }
-
- @Override
- public void addNavTrail(NavTree root)
- {
- root.addChild("TCR Data Export"); //necessary to set page title, it seems
- }
- }
-
public static class AssayRecord
{
private Integer _rowId;
@@ -453,54 +229,6 @@ public void setFraction(Double fraction)
}
}
- public static class ExportAlignmentsForm
- {
- private Integer[] _assayRowIds;
- private String schemaName;
- private String _cdr3Equals;
- private String _readContains;
-
- public Integer[] getAssayRowIds()
- {
- return _assayRowIds;
- }
-
- public void setAssayRowIds(Integer[] assayRowIds)
- {
- _assayRowIds = assayRowIds;
- }
-
- public String getSchemaName()
- {
- return schemaName;
- }
-
- public void setSchemaName(String schemaName)
- {
- this.schemaName = schemaName;
- }
-
- public String getCdr3Equals()
- {
- return _cdr3Equals;
- }
-
- public void setCdr3Equals(String cdr3Equals)
- {
- _cdr3Equals = cdr3Equals;
- }
-
- public String getReadContains()
- {
- return _readContains;
- }
-
- public void setReadContains(String readContains)
- {
- _readContains = readContains;
- }
- }
-
@RequiresPermission(ReadPermission.class)
@IgnoresTermsOfUse
public static class DownloadSequenceAction extends ExportAction
@@ -634,7 +362,7 @@ public void export(DownloadCloneMaterialsForm form, HttpServletResponse response
}
PageFlowUtil.prepareResponseForFile(response, Collections.emptyMap(), "TCR_Data.fasta", true);
- if (fasta.length() == 0)
+ if (fasta.isEmpty())
{
response.getOutputStream().write("No data found".getBytes(StringUtilsLabKey.DEFAULT_CHARSET));
}
@@ -645,300 +373,6 @@ public void export(DownloadCloneMaterialsForm form, HttpServletResponse response
}
}
- @RequiresPermission(ReadPermission.class)
- @IgnoresTermsOfUse
- public static class DownloadCloneMaterials extends ExportAction
- {
- @Override
- public void export(DownloadCloneMaterialsForm form, HttpServletResponse response, BindException errors) throws Exception
- {
- Container target = getContainer().isWorkbook() ? getContainer().getParent() : getContainer();
- UserSchema us = QueryService.get().getUserSchema(getUser(), target, form.getSchemaName());
- if (us == null)
- {
- errors.reject(ERROR_MSG, "Unable to find schema: " + form.getSchemaName());
- return;
- }
-
- TableInfo assayData = us.getTable(form.getQueryName());
- if (assayData == null)
- {
- errors.reject(ERROR_MSG, "Unable to find table: " + form.getQueryName());
- return;
- }
-
- List rowIds = Arrays.asList(form.getRowId());
- if (rowIds.isEmpty())
- {
- errors.reject(ERROR_MSG, "No rows provided");
- return;
- }
-
- // find distinct analyses for assay rows and primary segments
- SimpleFilter assayFilter = new SimpleFilter(FieldKey.fromString("rowId"), rowIds, CompareType.IN);
- Map cols = QueryService.get().getColumns(assayData, PageFlowUtil.set(
- FieldKey.fromString("analysisId"),
- FieldKey.fromString("samplename"),
- FieldKey.fromString("sequence"),
- FieldKey.fromString("cdr3"),
- FieldKey.fromString("vHit"),
- FieldKey.fromString("jHit"),
- FieldKey.fromString("dHit"),
- FieldKey.fromString("cHit"),
- FieldKey.fromString("cloneId"),
- FieldKey.fromString("sequence"),
- FieldKey.fromString("clonesFile"),
- FieldKey.fromString("libraryId/libraryId")));
-
- TableSelector ts = new TableSelector(assayData, cols.values(), assayFilter, null);
- Set segmentsByName = new HashSet<>();
- Map> segmentsByLibrary = new IntHashMap<>();
-
- Map> clnaToCloneMap = new IntHashMap<>();
- Map clnaToCDR3Map = new StringHashMap<>();
- StringBuilder imputedSequences = new StringBuilder();
- Set analyses = new IntHashSet();
- final String[] segmentFields = new String[]{"vHit", "jHit", "cHit"};
- ts.forEachResults(rs -> {
- Integer libraryId = rs.getObject(FieldKey.fromString("libraryId/libraryId")) == null ? null : rs.getInt(FieldKey.fromString("libraryId/libraryId"));
- for (String fn : segmentFields)
- {
- if (rs.getString(FieldKey.fromString(fn)) != null)
- {
- if (libraryId != null)
- {
- Set map = segmentsByLibrary.getOrDefault(libraryId, new HashSet<>());
- map.add(StringUtils.trimToNull(rs.getString(FieldKey.fromString(fn))));
- segmentsByLibrary.put(libraryId, map);
- }
- else
- {
- segmentsByName.add(StringUtils.trimToNull(rs.getString(FieldKey.fromString(fn))));
- }
- }
- }
-
- if (rs.getObject(FieldKey.fromString("analysisId")) != null)
- {
- analyses.add(rs.getInt(FieldKey.fromString("analysisId")));
- }
-
- if (rs.getObject(FieldKey.fromString("sequence")) != null)
- {
- imputedSequences.append(">").append(rs.getString(FieldKey.fromString("sampleName"))).append("_").append(rs.getString(FieldKey.fromString("cdr3"))).append("\n");
- imputedSequences.append(rs.getString(FieldKey.fromString("sequence"))).append("\n");
- }
-
- // This applies to MiXCR
- if (rs.getObject(FieldKey.fromString("cloneId")) != null && rs.getObject(FieldKey.fromString("clonesFile")) != null)
- {
- Integer key = rs.getInt(FieldKey.fromString("clonesFile"));
- Set set = clnaToCloneMap.containsKey(key) ? clnaToCloneMap.get(key) : new HashSet<>();
- set.add(rs.getString(FieldKey.fromString("cloneId")));
-
- clnaToCloneMap.put(key, set);
-
- clnaToCDR3Map.put(key + "_" + rs.getString(FieldKey.fromString("cloneId")), rs.getString(FieldKey.fromString("cdr3")));
- }
- });
-
- if (analyses.isEmpty())
- {
- errors.reject(ERROR_MSG, "Unable to find analyses for rows");
- return;
- }
-
- // then find all segments from these analyses
- SimpleFilter assayFilter2 = new SimpleFilter(FieldKey.fromString("analysisId"), analyses, CompareType.IN);
- new TableSelector(assayData, cols.values(), assayFilter2, null).forEachResults(rs -> {
- Integer libraryId = rs.getObject(FieldKey.fromString("libraryId/libraryId")) == null ? null : rs.getInt(FieldKey.fromString("libraryId/libraryId"));
- for (String fn : segmentFields)
- {
- if (rs.getString(FieldKey.fromString(fn)) != null)
- {
- if (libraryId != null)
- {
- Set map = segmentsByLibrary.getOrDefault(libraryId, new HashSet<>());
- map.add(StringUtils.trimToNull(rs.getString(FieldKey.fromString(fn))));
- segmentsByLibrary.put(libraryId, map);
- }
- else
- {
- segmentsByName.add(StringUtils.trimToNull(rs.getString(FieldKey.fromString(fn))));
- }
- }
- }
- });
-
- // look up segments in NT table
- Set missingSegments = new HashSet<>(segmentsByName);
- for (int libraryId : segmentsByLibrary.keySet())
- {
- missingSegments.addAll(segmentsByLibrary.get(libraryId));
- }
-
- StringBuilder fasta = new StringBuilder();
- if (!segmentsByLibrary.isEmpty())
- {
- for (int libraryId : segmentsByLibrary.keySet())
- {
- SimpleFilter ntFilter = new SimpleFilter(FieldKey.fromString("ref_nt_id/name"), segmentsByLibrary.get(libraryId), CompareType.IN);
- ntFilter.addCondition(FieldKey.fromString("ref_nt_id/datedisabled"), null, CompareType.ISBLANK);
- ntFilter.addCondition(FieldKey.fromString("library_id"), libraryId, CompareType.EQUAL);
- new TableSelector(QueryService.get().getUserSchema(getUser(), target, "sequenceanalysis").getTable("reference_library_members"), PageFlowUtil.set("ref_nt_id"), ntFilter, null).forEachResults(rs -> {
- RefNtSequenceModel nt = RefNtSequenceModel.getForRowId(rs.getInt(FieldKey.fromString("ref_nt_id")));
- fasta.append(">").append(nt.getName() + (nt.getSpecies() != null ? "-" + nt.getSpecies() : "")).append('\n').append(nt.getSequence()).append('\n');
- missingSegments.remove(nt.getName());
- });
- }
- }
-
- if (!segmentsByName.isEmpty())
- {
- SimpleFilter ntFilter = new SimpleFilter(FieldKey.fromString("name"), segmentsByName, CompareType.IN);
- ntFilter.addCondition(FieldKey.fromString("datedisabled"), null, CompareType.ISBLANK);
- new TableSelector(QueryService.get().getUserSchema(getUser(), target, "sequenceanalysis").getTable("ref_nt_sequences"), PageFlowUtil.set("rowid"), ntFilter, null).forEachResults(rs -> {
- RefNtSequenceModel nt = RefNtSequenceModel.getForRowId(rs.getInt(FieldKey.fromString("rowid")));
- fasta.append(">").append(nt.getName() + (nt.getSpecies() != null ? "-" + nt.getSpecies() : "")).append('\n').append(nt.getSequence()).append('\n');
- missingSegments.remove(nt.getName());
- });
- }
-
- if (!missingSegments.isEmpty())
- {
- logger.error("Unable to find the following NT sequences: [" + StringUtils.join(missingSegments, "],[") + "]");
- }
-
- // then grab actual Overlapping Contigs record(s). only bother grabbing if FASTA
- SimpleFilter outputFilter = new SimpleFilter(FieldKey.fromString("analysis_id"), analyses, CompareType.IN);
- outputFilter.addCondition(FieldKey.fromString("category"), "Overlapping Contigs");
-
- Set files = new HashSet<>();
- new TableSelector(QueryService.get().getUserSchema(getUser(), target, "sequenceanalysis").getTable("outputfiles"), PageFlowUtil.set("dataid"), outputFilter, null).forEachResults(rs -> {
- ExpData d = ExperimentService.get().getExpData(rs.getInt(FieldKey.fromString("dataid")));
- if (d != null && d.getFile().exists())
- {
- if (FASTA.isType(d.getFile()))
- {
- files.add(d.getFile());
- }
- }
- });
-
- //then exportReadsForClones:
- for (Integer expData : clnaToCloneMap.keySet())
- {
- MiXCRWrapper wrapper = new MiXCRWrapper(_log);
- ExpData d = ExperimentService.get().getExpData(expData);
- if (d == null)
- {
- _log.error("Unable to find exp data with ID: " + expData);
- continue;
- }
-
- if (d.getFile() == null || !d.getFile().exists())
- {
- _log.error("File not found for ExpData: " + (d.getFile() == null ? expData : d.getFile().getPath()));
- continue;
- }
-
- List args = new ArrayList<>();
- args.add("-s");
- args.add("--id");
- args.addAll(clnaToCloneMap.get(expData));
-
- String basename = SequenceAnalysisService.get().getUnzippedBaseName(d.getFile().getName()) + ".readsForClones";
- File fqBase = new File(FileUtils.getTempDirectory(), basename + ".fastq.gz");
-
- wrapper.doExportReadsForClones(d.getFile(), fqBase, args);
-
- for (String cloneId : clnaToCloneMap.get(expData))
- {
- String cdr3 = clnaToCDR3Map.get(expData + "_" + cloneId);
-
- File fq1 = new File(fqBase.getParentFile(), basename + "_cln" + cloneId + "_R1.fastq.gz");
- if (!fq1.exists())
- {
- _log.error("unable to find file: " + fq1.getPath());
- }
- else
- {
- File fq1m = new File(fqBase.getParentFile(), basename + "_cln" + cloneId + "." + cdr3 + ".R1.fastq.gz");
- FileUtils.moveFile(fq1, fq1m);
-
- files.add(fq1m);
- }
-
- File fq2 = new File(fqBase.getParentFile(), basename + "_cln" + cloneId + "_R2.fastq.gz");
- if (!fq2.exists())
- {
- _log.error("unable to find file: " + fq2.getPath());
- }
- else
- {
- File fq2m = new File(fqBase.getParentFile(), basename + "_cln" + cloneId + "." + cdr3 + ".R2.fastq.gz");
- FileUtils.moveFile(fq2, fq2m);
-
- files.add(fq2m);
- }
- }
- }
-
- PageFlowUtil.prepareResponseForFile(response, Collections.emptyMap(), "Clones.zip", true);
- Set distinctNames = new HashSet<>();
- try (ZipOutputStream zOut = new ZipOutputStream(response.getOutputStream()))
- {
- //the segments:
- ZipEntry fileEntryFasta = new ZipEntry("segments.fasta");
- distinctNames.add("segments.fasta");
-
- zOut.putNextEntry(fileEntryFasta);
- zOut.write(fasta.toString().getBytes(StringUtilsLabKey.DEFAULT_CHARSET));
- zOut.closeEntry();
-
- //the FL imputed clones:
- ZipEntry fileEntryFasta2 = new ZipEntry("imputedClones.fasta");
- distinctNames.add("imputedClones.fasta");
-
- zOut.putNextEntry(fileEntryFasta2);
- zOut.write(imputedSequences.toString().getBytes(StringUtilsLabKey.DEFAULT_CHARSET));
- zOut.closeEntry();
-
- for (File f : files)
- {
- String name = getUnique(f.getName(), distinctNames);
- ZipEntry fileEntry = new ZipEntry(name);
- zOut.putNextEntry(fileEntry);
-
- try (FileInputStream in = new FileInputStream(f))
- {
- IOUtils.copy(in, zOut);
- zOut.closeEntry();
- }
- catch (Exception e)
- {
- _log.error(e.getMessage(), e);
- }
- }
- }
- }
-
- private String getUnique(String name, Set distinctNames)
- {
- int i = 1;
- String newName = name;
- while (distinctNames.contains(newName))
- {
- newName = FileUtil.getBaseName(name) + "." + i + "." + FileUtil.getExtension(name);
- i++;
- }
-
- distinctNames.add(newName);
-
- return newName;
- }
- }
-
public static class DownloadCloneMaterialsForm
{
private String[] _rowId;
@@ -975,64 +409,4 @@ public void setQueryName(String queryName)
_queryName = queryName;
}
}
-
- @RequiresPermission(AdminPermission.class)
- public class CreateGenomeFromMixcrAction extends ConfirmAction
- {
- @Override
- public ModelAndView getConfirmView(CreateGenomeFromMixcrForm form, BindException errors) throws Exception
- {
- setTitle("Create Genome from MiXCR Library");
-
- HtmlView view = new HtmlView("This will create a reference genome from the selected MiXCR library JSON. Note: if there is an existing sequence in this folder with the same name and sequence, it will be re-used rather than creating a new sequence. If there is an existing record of the same name, but with a different shorter sequence, that sequence will be marked as disabled. Do you want to continue?");
- return view;
- }
-
- @Override
- public boolean handlePost(CreateGenomeFromMixcrForm form, BindException errors) throws Exception
- {
- try
- {
- TCRdbManager.get().createGenomeFromMixcrDb(form.getRowId(), getUser(), getContainer());
- }
- catch (Exception e)
- {
- _log.error(e.getMessage(), e);
- throw e;
- }
-
- return true;
- }
-
- @Override
- public void validateCommand(CreateGenomeFromMixcrForm form, Errors errors)
- {
- if (form.getRowId() == null || form.getRowId() == 0)
- {
- errors.reject(ERROR_MSG, "Must provide the library row Id");
- }
- }
-
- @NotNull
- @Override
- public URLHelper getSuccessURL(CreateGenomeFromMixcrForm form)
- {
- return QueryService.get().urlFor(getUser(), getContainer(), QueryAction.executeQuery, TCRdbSchema.NAME, TCRdbSchema.TABLE_MIXCR_LIBRARIES);
- }
- }
-
- public static class CreateGenomeFromMixcrForm
- {
- private Integer _rowId;
-
- public Integer getRowId()
- {
- return _rowId;
- }
-
- public void setRowId(Integer rowId)
- {
- _rowId = rowId;
- }
- }
}
diff --git a/tcrdb/src/org/labkey/tcrdb/TCRdbManager.java b/tcrdb/src/org/labkey/tcrdb/TCRdbManager.java
deleted file mode 100644
index e49dc1c74..000000000
--- a/tcrdb/src/org/labkey/tcrdb/TCRdbManager.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (c) 2015 LabKey Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.labkey.tcrdb;
-
-import com.milaboratory.core.sequence.NucleotideSequence;
-import io.repseq.core.GeneFeature;
-import io.repseq.core.VDJCGene;
-import io.repseq.core.VDJCLibrary;
-import io.repseq.core.VDJCLibraryRegistry;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.labkey.api.collections.CaseInsensitiveHashMap;
-import org.labkey.api.data.Container;
-import org.labkey.api.data.ContainerManager;
-import org.labkey.api.data.SimpleFilter;
-import org.labkey.api.data.TableInfo;
-import org.labkey.api.data.TableSelector;
-import org.labkey.api.module.ModuleLoader;
-import org.labkey.api.query.BatchValidationException;
-import org.labkey.api.query.FieldKey;
-import org.labkey.api.query.InvalidKeyException;
-import org.labkey.api.query.QueryService;
-import org.labkey.api.query.QueryUpdateServiceException;
-import org.labkey.api.query.UserSchema;
-import org.labkey.api.security.User;
-import org.labkey.api.sequenceanalysis.GenomeTrigger;
-import org.labkey.api.sequenceanalysis.RefNtSequenceModel;
-import org.labkey.api.sequenceanalysis.SequenceAnalysisService;
-import org.labkey.api.util.PageFlowUtil;
-import org.labkey.tcrdb.query.MixcrLibrary;
-
-import java.io.File;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-public class TCRdbManager
-{
- private static final TCRdbManager _instance = new TCRdbManager();
- private static final Logger _log = LogManager.getLogger(TCRdbManager.class);
-
- private TCRdbManager()
- {
-
- }
-
- public static TCRdbManager get()
- {
- return _instance;
- }
-
- public void createGenomeFromMixcrDb(int mixcrRowId, User u, Container c) throws Exception
- {
- MixcrLibrary lib = new TableSelector(TCRdbSchema.getInstance().getSchema().getTable(TCRdbSchema.TABLE_MIXCR_LIBRARIES)).getObject(mixcrRowId, MixcrLibrary.class);
- if (lib == null)
- {
- throw new IllegalArgumentException("Unable to find MiXCR library: " + mixcrRowId);
- }
-
- File jsonFile = lib.getJsonFile();
- if (jsonFile == null)
- {
- throw new IllegalArgumentException("Unable to find JSON for MiXCR library: " + mixcrRowId);
- }
-
- if (lib.getLibraryId() != null)
- {
- throw new IllegalArgumentException("MiXCR library already has a genome associated with it: " + mixcrRowId);
- }
-
- Container target = c.isWorkbookOrTab() ? c.getParent() : c;
- UserSchema us = QueryService.get().getUserSchema(u, target, TCRdbSchema.SEQUENCE_ANALYSIS);
- TableInfo refNt = us.getTable("ref_nt_sequences");
-
- try
- {
- List sequences = new ArrayList<>();
-
- VDJCLibraryRegistry reg = VDJCLibraryRegistry.getDefault();
- reg.addPathResolver(jsonFile.getParentFile().getPath());
-
- VDJCLibrary library = reg.getLibrary(lib.getLibraryName(), lib.getSpecies());
- String species = StringUtils.capitalize(lib.getSpecies());
-
- OUTER: for (VDJCGene gene : library.getGenes())
- {
- String name = gene.getName();
- Map regions = new LinkedHashMap<>();
- switch (gene.getGeneType())
- {
- case Variable:
- regions.put("L1+VExon2", new GeneFeature(GeneFeature.L1, GeneFeature.VExon2));
- regions.put("VRegion", GeneFeature.VRegion);
- break;
- case Joining:
- regions.put("JRegion", GeneFeature.JRegion);
- break;
- case Diversity:
- regions.put("DRegion", GeneFeature.DRegion);
- break;
- case Constant:
- regions.put("CExon1", GeneFeature.CExon1);
- break;
- }
-
- String seq = null;
- String regionUsed = null;
- for (String regionName : regions.keySet())
- {
- GeneFeature region = regions.get(regionName);
- try
- {
- NucleotideSequence nt = gene.getFeature(region);
- if (nt != null)
- {
- seq = nt.toString();
- regionUsed = regionName;
- break;
- }
- }
- catch (Exception e)
- {
- _log.error(e.getMessage(), e);
- }
- }
-
- if (seq == null)
- {
- _log.error("Unable to find segment for sequence: " + gene.getName());
- continue;
- }
-
- List comments = new ArrayList<>();
- comments.add("Region: " + regionUsed);
- if (!gene.isFunctional())
- {
- comments.add("Functional: " + gene.isFunctional());
- }
-
- if (gene.getData().getMeta() != null && gene.getData().getMeta().get("In_IMGT") != null)
- {
- comments.add("In IMGT: " + StringUtils.join(gene.getData().getMeta().get("In_IMGT"), ","));
-
- if (gene.getData().getMeta().get("ExtendedFromIMGT") != null)
- {
- comments.add("ExtendedFromIMGT: " + StringUtils.join(gene.getData().getMeta().get("ExtendedFromIMGT"), ","));
- }
- }
-
- SimpleFilter filter = new SimpleFilter(FieldKey.fromString("name"), name);
- filter.addCondition(FieldKey.fromString("species"), species);
- TableSelector ts = new TableSelector(refNt, filter, null);
- if (ts.exists())
- {
- List refs = ts.getArrayList(RefNtSequenceModel.class);
- for (RefNtSequenceModel ref : refs)
- {
- if (seq.equals(ref.getSequence()))
- {
- _log.info("Using existing: " + ref.getName());
- sequences.add(ref.getRowid());
-
- //update fields, as needed:
- Map toUpdate = new CaseInsensitiveHashMap<>();
- if (!"TCR".equals(ref.getCategory()))
- {
- toUpdate.put("category", "TCR");
-
- }
-
- if (ref.getDatedisabled() != null)
- {
- toUpdate.put("datedisabled", null);
- }
-
- if (ref.getDisabledby() != null)
- {
- toUpdate.put("disabledby", null);
- }
-
- if (!gene.getGeneName().equals(ref.getSubset()))
- {
- toUpdate.put("subset", gene.getGeneName());
- }
-
- String locus = StringUtils.join(gene.getChains(), ",");
- if (!locus.equals(ref.getLocus()))
- {
- toUpdate.put("locus", locus);
- }
-
- if (!gene.getFamilyName().equals(ref.getLineage()))
- {
- toUpdate.put("lineage", gene.getFamilyName());
- }
-
- if (!comments.equals(ref.getComments()))
- {
- toUpdate.put("comments", comments);
- }
-
- if (!toUpdate.isEmpty())
- {
- _log.info("Updating existing record: " + ref.getName());
- toUpdate.put("rowid", ref.getRowid());
- Map oldKeys = new CaseInsensitiveHashMap<>();
- oldKeys.put("rowid", ref.getRowid());
- refNt.getUpdateService().updateRows(u, ContainerManager.getForId(ref.getContainer()), List.of(toUpdate), List.of(oldKeys), null, null);
- }
-
- continue OUTER;
- }
- }
- }
-
- //otherwise create new:
- Map row = new CaseInsensitiveHashMap<>();
- row.put("name", name);
- row.put("category", "TCR");
- row.put("species", species);
- row.put("subset", gene.getGeneName());
- row.put("locus", StringUtils.join(gene.getChains(), ","));
- row.put("lineage", gene.getFamilyName());
- row.put("container", lib.getContainer());
- row.put("sequence", seq);
- row.put("comments", StringUtils.join(comments, "\n"));
-
- BatchValidationException errors = new BatchValidationException();
- List