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 |
Holds all information about a sequencing run. Validation will |
6202 |
09 Apr 21 |
nicklas |
be done at construction and errors are reported to |
6202 |
09 Apr 21 |
nicklas |
the JsonSection. Check the 'valid' flag before using |
6202 |
09 Apr 21 |
nicklas |
the information. |
6202 |
09 Apr 21 |
nicklas |
23 |
|
6202 |
09 Apr 21 |
nicklas |
NOTE! We do not read the "Model" entry from this |
6202 |
09 Apr 21 |
nicklas |
section. Instead we use the "SerialNumber" entry to locate |
6202 |
09 Apr 21 |
nicklas |
a Hardware item (Sequencer) in our database and take the |
6202 |
09 Apr 21 |
nicklas |
"HardwareMode" annotation from that item. |
6202 |
09 Apr 21 |
nicklas |
28 |
|
6202 |
09 Apr 21 |
nicklas |
@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 |
Information about the sequencer machine that was used. We |
6202 |
09 Apr 21 |
nicklas |
use the serial number to locate a Hardware item in our |
6202 |
09 Apr 21 |
nicklas |
database. It is an error if no sequencer is found. We also |
6202 |
09 Apr 21 |
nicklas |
get "HardwareModel" and "FlowCellType" annotations from the |
6202 |
09 Apr 21 |
nicklas |
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 |
If there is no value in the JSON we can use the value from the FASTQ |
6955 |
12 Dec 22 |
nicklas |
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 |
Validator for sequencing RunNumber that can use the value from the |
6955 |
12 Dec 22 |
nicklas |
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 |
|