extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/SequencingRunInfo.java

Code
Comments
Other
Rev Date Author Line
6202 09 Apr 21 nicklas 1 package net.sf.basedb.reggie.plugins.cmd;
6202 09 Apr 21 nicklas 2
6202 09 Apr 21 nicklas 3 import java.util.Date;
6202 09 Apr 21 nicklas 4 import java.util.List;
6202 09 Apr 21 nicklas 5
6202 09 Apr 21 nicklas 6 import net.sf.basedb.core.DbControl;
6205 12 Apr 21 nicklas 7 import net.sf.basedb.core.DerivedBioAssay;
6202 09 Apr 21 nicklas 8 import net.sf.basedb.core.Hardware;
6202 09 Apr 21 nicklas 9 import net.sf.basedb.core.ItemQuery;
6202 09 Apr 21 nicklas 10 import net.sf.basedb.core.query.Annotations;
6202 09 Apr 21 nicklas 11 import net.sf.basedb.core.query.Expressions;
6202 09 Apr 21 nicklas 12 import net.sf.basedb.core.query.Hql;
6202 09 Apr 21 nicklas 13 import net.sf.basedb.core.query.Restrictions;
6202 09 Apr 21 nicklas 14 import net.sf.basedb.reggie.Reggie;
6202 09 Apr 21 nicklas 15 import net.sf.basedb.reggie.dao.Annotationtype;
6202 09 Apr 21 nicklas 16 import net.sf.basedb.reggie.dao.Subtype;
6202 09 Apr 21 nicklas 17
6202 09 Apr 21 nicklas 18 /**
6202 09 Apr 21 nicklas 19   Holds all information about a sequencing run. Validation will
6202 09 Apr 21 nicklas 20   be done at construction and errors are reported to
6202 09 Apr 21 nicklas 21   the JsonSection. Check the 'valid' flag before using
6202 09 Apr 21 nicklas 22   the information.
6202 09 Apr 21 nicklas 23
6202 09 Apr 21 nicklas 24   NOTE! We do not read the "Model" entry from this
6202 09 Apr 21 nicklas 25   section. Instead we use the "SerialNumber" entry to locate 
6202 09 Apr 21 nicklas 26   a Hardware item (Sequencer) in our database and take the 
6202 09 Apr 21 nicklas 27   "HardwareMode" annotation from that item.
6202 09 Apr 21 nicklas 28
6202 09 Apr 21 nicklas 29   @since 4.32
6202 09 Apr 21 nicklas 30 */
6202 09 Apr 21 nicklas 31 public class SequencingRunInfo 
6202 09 Apr 21 nicklas 32 {
6202 09 Apr 21 nicklas 33
6205 12 Apr 21 nicklas 34   public DerivedBioAssay sequencingRun;
6202 09 Apr 21 nicklas 35   public SequencerInfo sequencer;
6202 09 Apr 21 nicklas 36   public String position;
6202 09 Apr 21 nicklas 37   public Integer runNumber;
6202 09 Apr 21 nicklas 38   public Date startDate;
6202 09 Apr 21 nicklas 39   public Date endDate;
6202 09 Apr 21 nicklas 40   public String operator;
6202 09 Apr 21 nicklas 41   
6202 09 Apr 21 nicklas 42   public boolean valid;
6202 09 Apr 21 nicklas 43
6955 12 Dec 22 nicklas 44   public SequencingRunInfo(JsonSection section, FastqInfo fastqInfo, FlowCellInfo flowCellInfo, PoolInfo pool, MainInfo main)
6202 09 Apr 21 nicklas 45   {
6205 12 Apr 21 nicklas 46     if (section != null)
6202 09 Apr 21 nicklas 47     {
6955 12 Dec 22 nicklas 48       sequencer = section.getRequiredEntry("SerialNumber", new SequencerInfo(fastqInfo));
6955 12 Dec 22 nicklas 49       if (sequencer != null && fastqInfo != null && fastqInfo.flowCellId != null)
6955 12 Dec 22 nicklas 50       {
6955 12 Dec 22 nicklas 51         if (!sequencer.serialNo.equals(fastqInfo.sequencerSerial))
6955 12 Dec 22 nicklas 52         {
6955 12 Dec 22 nicklas 53           section.addErrorMessage("SequencingRun.SerialNumber mismatch: JSON="+sequencer.serialNo+"; FASTQ="+fastqInfo.sequencerSerial);
6955 12 Dec 22 nicklas 54         }
6955 12 Dec 22 nicklas 55       }
6955 12 Dec 22 nicklas 56
6205 12 Apr 21 nicklas 57       position = section.getRequiredEntry("Position", PatternValidator.SEQUENCER_POSITION);
6955 12 Dec 22 nicklas 58       runNumber = section.getRequiredEntry("RunNumber", new RunNumberValidator(fastqInfo));
6955 12 Dec 22 nicklas 59       if (runNumber != null && fastqInfo != null && fastqInfo.runNumber != null)
6955 12 Dec 22 nicklas 60       {
6955 12 Dec 22 nicklas 61         if (!runNumber.toString().equals(fastqInfo.runNumber))
6955 12 Dec 22 nicklas 62         {
6955 12 Dec 22 nicklas 63           section.addErrorMessage("SequencingRun.RunNumber mismatch: JSON="+runNumber+"; FASTQ="+fastqInfo.runNumber);
6955 12 Dec 22 nicklas 64         }
6955 12 Dec 22 nicklas 65       }
6893 25 Nov 22 nicklas 66       startDate = section.getRequiredEntry("StartDate", DateValidator.YYYY_MM_DD.warnIfFutureOrOlder(pool!=null?pool.poolDate:null, main.refDate));
6893 25 Nov 22 nicklas 67       endDate = section.getRequiredEntry("EndDate", DateValidator.YYYY_MM_DD.warnIfFutureOrOlder(startDate, main.refDate));
6212 14 Apr 21 nicklas 68       operator = section.getOptionalEntry("Operator", null);
6205 12 Apr 21 nicklas 69       if (flowCellInfo.flowCell != null) 
6205 12 Apr 21 nicklas 70       {
6205 12 Apr 21 nicklas 71         sequencingRun = findExistingSeqRun(flowCellInfo, section);
6205 12 Apr 21 nicklas 72       }
6202 09 Apr 21 nicklas 73     }
6205 12 Apr 21 nicklas 74     valid = section != null && !section.hasError();
6202 09 Apr 21 nicklas 75   }
6202 09 Apr 21 nicklas 76   
6205 12 Apr 21 nicklas 77   private DerivedBioAssay findExistingSeqRun(FlowCellInfo flowCellInfo, JsonSection section)
6205 12 Apr 21 nicklas 78   {
6205 12 Apr 21 nicklas 79     DerivedBioAssay seqRun = null;
6205 12 Apr 21 nicklas 80     DbControl dc = section.getFile().dc();
6205 12 Apr 21 nicklas 81     ItemQuery<DerivedBioAssay> query = flowCellInfo.flowCell.getRootDerivedBioAssays();
6205 12 Apr 21 nicklas 82     query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
6205 12 Apr 21 nicklas 83     Subtype.SEQUENCING_RUN.addFilter(dc, query);
6205 12 Apr 21 nicklas 84     List<DerivedBioAssay> list = query.list(dc);
6205 12 Apr 21 nicklas 85     if (list.size() > 1)
6205 12 Apr 21 nicklas 86     {
6205 12 Apr 21 nicklas 87       section.addErrorMessage("Found "+list.size()+" sequencing runs for FlowCellID="+flowCellInfo.flowCellId);
6205 12 Apr 21 nicklas 88     }
6205 12 Apr 21 nicklas 89     else if (list.size() == 1)
6205 12 Apr 21 nicklas 90     {
6205 12 Apr 21 nicklas 91       seqRun = list.get(0);
6205 12 Apr 21 nicklas 92     }
6205 12 Apr 21 nicklas 93     return seqRun;
6205 12 Apr 21 nicklas 94   }
6205 12 Apr 21 nicklas 95   
6202 09 Apr 21 nicklas 96   /**
6202 09 Apr 21 nicklas 97     Information about the sequencer machine that was used. We
6202 09 Apr 21 nicklas 98     use the serial number to locate a Hardware item in our 
6202 09 Apr 21 nicklas 99     database. It is an error if no sequencer is found. We also
6202 09 Apr 21 nicklas 100     get "HardwareModel" and "FlowCellType" annotations from the
6202 09 Apr 21 nicklas 101     sequencer.
6202 09 Apr 21 nicklas 102   */
6202 09 Apr 21 nicklas 103   public static class SequencerInfo
6202 09 Apr 21 nicklas 104     implements ValueValidator<String, SequencerInfo>
6202 09 Apr 21 nicklas 105   {
6955 12 Dec 22 nicklas 106     private final FastqInfo fastqInfo;
6955 12 Dec 22 nicklas 107     
6202 09 Apr 21 nicklas 108     public Hardware sequencer;
6202 09 Apr 21 nicklas 109     public String serialNo;
6202 09 Apr 21 nicklas 110     public String flowCellType;
6202 09 Apr 21 nicklas 111     public String model;
6202 09 Apr 21 nicklas 112     
6955 12 Dec 22 nicklas 113     public SequencerInfo(FastqInfo fastqInfo)
6955 12 Dec 22 nicklas 114     {
6955 12 Dec 22 nicklas 115       this.fastqInfo = fastqInfo;
6955 12 Dec 22 nicklas 116     }
6955 12 Dec 22 nicklas 117     
6202 09 Apr 21 nicklas 118     @Override
6202 09 Apr 21 nicklas 119     public SequencerInfo isValid(DbControl dc, String serialNo, JsonSection section, String entryKey)
6202 09 Apr 21 nicklas 120     {
6202 09 Apr 21 nicklas 121       if (PatternValidator.SERIAL_NO.isValid(dc, serialNo, section, entryKey) == null) return null;
6202 09 Apr 21 nicklas 122       
6202 09 Apr 21 nicklas 123       ItemQuery<Hardware> query = Hardware.getQuery();
6202 09 Apr 21 nicklas 124       query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
6202 09 Apr 21 nicklas 125       Subtype.SEQUENCER.addFilter(dc, query);
6202 09 Apr 21 nicklas 126       query.join(Annotations.innerJoin(Annotationtype.SERIAL_NUMBER.get(dc), "sn"));
6202 09 Apr 21 nicklas 127       query.restrict(Restrictions.eq(Hql.alias("sn"), Expressions.string(serialNo)));
6202 09 Apr 21 nicklas 128       List<Hardware> list = query.list(dc);
6202 09 Apr 21 nicklas 129       if (list.size() != 1)
6202 09 Apr 21 nicklas 130       {
6202 09 Apr 21 nicklas 131         if (list.size() > 1)
6202 09 Apr 21 nicklas 132         {
6202 09 Apr 21 nicklas 133           section.addErrorMessage("Found "+list.size()+" matches: Type=Sequencer; SerialNumber="+serialNo);
6202 09 Apr 21 nicklas 134         }
6202 09 Apr 21 nicklas 135         else
6202 09 Apr 21 nicklas 136         {
6202 09 Apr 21 nicklas 137           section.addErrorMessage("Sequencer not found: SerialNumber="+serialNo);
6202 09 Apr 21 nicklas 138         }
6202 09 Apr 21 nicklas 139         return null;
6202 09 Apr 21 nicklas 140       }
6202 09 Apr 21 nicklas 141       this.sequencer = list.get(0);
6202 09 Apr 21 nicklas 142       this.serialNo = serialNo;
6202 09 Apr 21 nicklas 143       this.flowCellType = (String)Annotationtype.FLOWCELL_TYPE.getAnnotationValue(dc, sequencer);
6202 09 Apr 21 nicklas 144       this.model = (String)Annotationtype.HARDWARE_MODEL.getAnnotationValue(dc, sequencer);
6202 09 Apr 21 nicklas 145       return this;
6202 09 Apr 21 nicklas 146     }
6202 09 Apr 21 nicklas 147     
6202 09 Apr 21 nicklas 148     @Override
6202 09 Apr 21 nicklas 149     public Class<String> getExpectedClass() 
6202 09 Apr 21 nicklas 150     {
6202 09 Apr 21 nicklas 151       return String.class;
6202 09 Apr 21 nicklas 152     }
6955 12 Dec 22 nicklas 153
6955 12 Dec 22 nicklas 154     /**
6955 12 Dec 22 nicklas 155       If there is no value in the JSON we can use the value from the FASTQ
6955 12 Dec 22 nicklas 156       but issue a warning message.
6955 12 Dec 22 nicklas 157     */
6955 12 Dec 22 nicklas 158     @Override
6955 12 Dec 22 nicklas 159     public Object preProcess(DbControl dc, Object serialNo, JsonSection section, String entryKey) 
6955 12 Dec 22 nicklas 160     {
6955 12 Dec 22 nicklas 161       String s = serialNo instanceof String ? (String)serialNo : null;
6955 12 Dec 22 nicklas 162       if ((s == null || s.length() == 0) && fastqInfo != null && fastqInfo.sequencerSerial != null)
6955 12 Dec 22 nicklas 163       {
6955 12 Dec 22 nicklas 164         serialNo = fastqInfo.sequencerSerial;
6955 12 Dec 22 nicklas 165         section.addWarningMessage("Missing SequencingRun.SerialNumber in JSON. Using value from FASTQ: " + serialNo);
6955 12 Dec 22 nicklas 166       }
6955 12 Dec 22 nicklas 167       return serialNo;
6955 12 Dec 22 nicklas 168     }
6955 12 Dec 22 nicklas 169     
6202 09 Apr 21 nicklas 170   }
6202 09 Apr 21 nicklas 171   
6955 12 Dec 22 nicklas 172   /**
6955 12 Dec 22 nicklas 173     Validator for sequencing RunNumber that can use the value from the
6955 12 Dec 22 nicklas 174     FASTQ headers if it is missing in the JSON file.
6955 12 Dec 22 nicklas 175   */
6955 12 Dec 22 nicklas 176   public static class RunNumberValidator
6955 12 Dec 22 nicklas 177     extends IntValidator
6955 12 Dec 22 nicklas 178   {
6202 09 Apr 21 nicklas 179
6955 12 Dec 22 nicklas 180     private final FastqInfo fastqInfo;
6955 12 Dec 22 nicklas 181     public RunNumberValidator(FastqInfo fastqInfo)
6955 12 Dec 22 nicklas 182     {
6955 12 Dec 22 nicklas 183       super(1, null);
6955 12 Dec 22 nicklas 184       this.fastqInfo = fastqInfo;
6955 12 Dec 22 nicklas 185     }
6955 12 Dec 22 nicklas 186     
6955 12 Dec 22 nicklas 187     @Override
6955 12 Dec 22 nicklas 188     public Object preProcess(DbControl dc, Object runNumber, JsonSection section, String entryKey) 
6955 12 Dec 22 nicklas 189     {
6955 12 Dec 22 nicklas 190       if ((runNumber == null || runNumber.toString().length() == 0) && fastqInfo != null && fastqInfo.runNumber != null)
6955 12 Dec 22 nicklas 191       {
6955 12 Dec 22 nicklas 192         runNumber = fastqInfo.runNumber;
6955 12 Dec 22 nicklas 193         section.addWarningMessage("Missing SequencingRun.RunNumber in JSON. Using value from FASTQ: " + runNumber);
6955 12 Dec 22 nicklas 194       }
6955 12 Dec 22 nicklas 195       return runNumber;
6955 12 Dec 22 nicklas 196     }
6955 12 Dec 22 nicklas 197     
6955 12 Dec 22 nicklas 198   }
6955 12 Dec 22 nicklas 199   
6202 09 Apr 21 nicklas 200 }
6202 09 Apr 21 nicklas 201
6202 09 Apr 21 nicklas 202