4795 |
08 May 18 |
olle |
1 |
package net.sf.basedb.meludi.dao; |
4795 |
08 May 18 |
olle |
2 |
|
4795 |
08 May 18 |
olle |
3 |
import java.util.ArrayList; |
4795 |
08 May 18 |
olle |
4 |
import java.util.List; |
4795 |
08 May 18 |
olle |
5 |
|
4831 |
05 Jun 18 |
olle |
6 |
import org.json.simple.JSONObject; |
4831 |
05 Jun 18 |
olle |
7 |
|
5468 |
04 Jun 19 |
olle |
8 |
import net.sf.basedb.core.AnnotationRestriction; |
4795 |
08 May 18 |
olle |
9 |
import net.sf.basedb.core.AnnotationSimpleRestriction; |
4899 |
10 Jul 18 |
olle |
10 |
import net.sf.basedb.core.AnnotationType; |
4795 |
08 May 18 |
olle |
11 |
import net.sf.basedb.core.DbControl; |
4795 |
08 May 18 |
olle |
12 |
import net.sf.basedb.core.Include; |
4795 |
08 May 18 |
olle |
13 |
import net.sf.basedb.core.InvalidDataException; |
4795 |
08 May 18 |
olle |
14 |
import net.sf.basedb.core.ItemQuery; |
4795 |
08 May 18 |
olle |
15 |
import net.sf.basedb.core.Operator; |
4795 |
08 May 18 |
olle |
16 |
import net.sf.basedb.core.PermissionDeniedException; |
4795 |
08 May 18 |
olle |
17 |
import net.sf.basedb.core.Sample; |
4868 |
25 Jun 18 |
olle |
18 |
import net.sf.basedb.core.SessionControl; |
4795 |
08 May 18 |
olle |
19 |
import net.sf.basedb.core.Type; |
4795 |
08 May 18 |
olle |
20 |
import net.sf.basedb.core.query.Annotations; |
4795 |
08 May 18 |
olle |
21 |
import net.sf.basedb.core.query.Expressions; |
4795 |
08 May 18 |
olle |
22 |
import net.sf.basedb.core.query.Hql; |
4795 |
08 May 18 |
olle |
23 |
import net.sf.basedb.core.query.Orders; |
4795 |
08 May 18 |
olle |
24 |
import net.sf.basedb.core.query.Restrictions; |
4831 |
05 Jun 18 |
olle |
25 |
import net.sf.basedb.meludi.JsonUtil; |
4795 |
08 May 18 |
olle |
26 |
import net.sf.basedb.meludi.Meludi; |
4795 |
08 May 18 |
olle |
27 |
import net.sf.basedb.meludi.ReservedItems; |
4795 |
08 May 18 |
olle |
28 |
import net.sf.basedb.util.MD5; |
4795 |
08 May 18 |
olle |
29 |
import net.sf.basedb.util.Values; |
4795 |
08 May 18 |
olle |
30 |
|
4795 |
08 May 18 |
olle |
31 |
/** |
4795 |
08 May 18 |
olle |
Class for loading information that is related to blood referral forms. |
4795 |
08 May 18 |
olle |
33 |
|
4795 |
08 May 18 |
olle |
@author nicklas |
4795 |
08 May 18 |
olle |
@since 2.2 |
4795 |
08 May 18 |
olle |
36 |
*/ |
4795 |
08 May 18 |
olle |
37 |
public class Blood |
4795 |
08 May 18 |
olle |
38 |
extends MeludiItem<Sample> |
4795 |
08 May 18 |
olle |
39 |
{ |
4795 |
08 May 18 |
olle |
40 |
|
4795 |
08 May 18 |
olle |
41 |
/** |
4795 |
08 May 18 |
olle |
Find blood information by case name. This method will check for |
4795 |
08 May 18 |
olle |
{@link Subtype#BLOOD} samples with a name matching the case name (eg. xxx.b) |
4795 |
08 May 18 |
olle |
If useBlodSampleAnnotation is set the lookup will use the 'BloodSample' annotation |
4795 |
08 May 18 |
olle |
when searching for samples. If the case name has a suffix 'C' only samples annotated |
4795 |
08 May 18 |
olle |
with BloodSample=PreNeo are considered. If no suffix is specified PreNeo samples |
4795 |
08 May 18 |
olle |
are ignored. |
4795 |
08 May 18 |
olle |
<p> |
4795 |
08 May 18 |
olle |
If exactly one match is found this is the search for blood sample. More than one |
4795 |
08 May 18 |
olle |
match is an error condition. No match indicates a case that has not yet been |
4795 |
08 May 18 |
olle |
registered (null is returned). |
4795 |
08 May 18 |
olle |
52 |
*/ |
4795 |
08 May 18 |
olle |
53 |
public static Blood findByCaseName(DbControl dc, String name, boolean useBloodSampleAnnotation) |
4795 |
08 May 18 |
olle |
54 |
{ |
4795 |
08 May 18 |
olle |
55 |
Blood bloodCase = null; |
4795 |
08 May 18 |
olle |
56 |
|
4877 |
27 Jun 18 |
olle |
57 |
SessionControl sc = dc.getSessionControl(); |
4795 |
08 May 18 |
olle |
58 |
boolean preNeo = name.endsWith("C"); |
4877 |
27 Jun 18 |
olle |
//if (name.length() > 7) name = name.substring(0, 7); |
4877 |
27 Jun 18 |
olle |
60 |
boolean bloodAndSampleItemPrefixesDiffer = Meludi.bloodAndSampleItemPrefixesDiffer(sc.getActiveProjectId()); |
4877 |
27 Jun 18 |
olle |
61 |
if (!bloodAndSampleItemPrefixesDiffer) |
4877 |
27 Jun 18 |
olle |
62 |
{ |
4877 |
27 Jun 18 |
olle |
63 |
name += ".b%"; |
4877 |
27 Jun 18 |
olle |
64 |
} |
4877 |
27 Jun 18 |
olle |
65 |
else |
4877 |
27 Jun 18 |
olle |
66 |
{ |
4877 |
27 Jun 18 |
olle |
67 |
name += ".%"; |
4877 |
27 Jun 18 |
olle |
68 |
} |
4868 |
25 Jun 18 |
olle |
69 |
|
4868 |
25 Jun 18 |
olle |
// Replace sample item prefix with blood item prefix |
4868 |
25 Jun 18 |
olle |
71 |
String sampleItemPrefix = Meludi.fetchSampleItemPrefix(sc.getActiveProjectId()); |
4868 |
25 Jun 18 |
olle |
72 |
String bloodItemPrefix = Meludi.fetchBloodItemPrefix(sc.getActiveProjectId()); |
4868 |
25 Jun 18 |
olle |
73 |
if (name.startsWith(sampleItemPrefix)) |
4868 |
25 Jun 18 |
olle |
74 |
{ |
4868 |
25 Jun 18 |
olle |
// Remove sample item prefix |
4868 |
25 Jun 18 |
olle |
76 |
name = name.substring(sampleItemPrefix.length()); |
4868 |
25 Jun 18 |
olle |
// Add blood item prefix |
4868 |
25 Jun 18 |
olle |
78 |
name = bloodItemPrefix + name; |
4868 |
25 Jun 18 |
olle |
79 |
} |
4868 |
25 Jun 18 |
olle |
80 |
|
4795 |
08 May 18 |
olle |
// Look for a blood case with the given name |
4795 |
08 May 18 |
olle |
82 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
83 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
84 |
bloodQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name, Type.STRING))); |
4795 |
08 May 18 |
olle |
85 |
|
4795 |
08 May 18 |
olle |
86 |
/* |
4795 |
08 May 18 |
olle |
if (useBloodSampleAnnotation) |
4795 |
08 May 18 |
olle |
88 |
{ |
4795 |
08 May 18 |
olle |
bloodQuery.join(Annotations.leftJoin(Annotationtype.BLOOD_SAMPLE.load(dc), "bs")); |
4795 |
08 May 18 |
olle |
if (preNeo) |
4795 |
08 May 18 |
olle |
91 |
{ |
4795 |
08 May 18 |
olle |
// Only look for samples with annotation BloodSample=PreNeo |
4795 |
08 May 18 |
olle |
bloodQuery.restrict(Restrictions.eq(Hql.alias("bs"), Expressions.string("PreNeo"))); |
4795 |
08 May 18 |
olle |
94 |
} |
4795 |
08 May 18 |
olle |
else |
4795 |
08 May 18 |
olle |
96 |
{ |
4795 |
08 May 18 |
olle |
// Only look for samples with annotation BloodSample=PreOp or missing |
4795 |
08 May 18 |
olle |
bloodQuery.restrict( |
4795 |
08 May 18 |
olle |
Restrictions.or( |
4795 |
08 May 18 |
olle |
Restrictions.eq(Hql.alias("bs"), null), |
4795 |
08 May 18 |
olle |
Restrictions.eq(Hql.alias("bs"), Expressions.string("PreOp")) |
4795 |
08 May 18 |
olle |
102 |
)); |
4795 |
08 May 18 |
olle |
103 |
} |
4795 |
08 May 18 |
olle |
104 |
} |
4795 |
08 May 18 |
olle |
105 |
*/ |
4795 |
08 May 18 |
olle |
106 |
|
4795 |
08 May 18 |
olle |
107 |
List<Sample> bloodCases = bloodQuery.list(dc); |
4795 |
08 May 18 |
olle |
108 |
|
4795 |
08 May 18 |
olle |
// ...if more than one is found, something is incorrectly registered... abort |
4795 |
08 May 18 |
olle |
110 |
if (bloodCases.size() > 1) |
4795 |
08 May 18 |
olle |
111 |
{ |
4795 |
08 May 18 |
olle |
112 |
throw new InvalidDataException( |
4795 |
08 May 18 |
olle |
113 |
"Found " + bloodCases.size() + " cases with the same name (" + name + |
4795 |
08 May 18 |
olle |
114 |
"). This wizard can't be used until that is corrected."); |
4795 |
08 May 18 |
olle |
115 |
} |
4795 |
08 May 18 |
olle |
116 |
|
4795 |
08 May 18 |
olle |
117 |
if (bloodCases.size() == 1) |
4795 |
08 May 18 |
olle |
118 |
{ |
4795 |
08 May 18 |
olle |
119 |
bloodCase = new Blood(bloodCases.get(0)); |
4795 |
08 May 18 |
olle |
120 |
} |
4795 |
08 May 18 |
olle |
121 |
|
4795 |
08 May 18 |
olle |
122 |
return bloodCase; |
4795 |
08 May 18 |
olle |
123 |
|
4795 |
08 May 18 |
olle |
124 |
} |
4899 |
10 Jul 18 |
olle |
125 |
|
4795 |
08 May 18 |
olle |
126 |
/** |
4795 |
08 May 18 |
olle |
Find all blood information by case name without filtering on the 'BloodSample' annotation. |
4795 |
08 May 18 |
olle |
This method will check for {@link Subtype#BLOOD} samples with a name matching the case name |
4795 |
08 May 18 |
olle |
(eg. xxx.b). |
4795 |
08 May 18 |
olle |
@since 2.11 |
4795 |
08 May 18 |
olle |
131 |
*/ |
4795 |
08 May 18 |
olle |
132 |
public static List<Blood> findAllByCaseName(DbControl dc, String name) |
4795 |
08 May 18 |
olle |
133 |
{ |
4899 |
10 Jul 18 |
olle |
134 |
List<Blood> bloodList = null; |
4899 |
10 Jul 18 |
olle |
135 |
|
4899 |
10 Jul 18 |
olle |
136 |
SessionControl sc = dc.getSessionControl(); |
4899 |
10 Jul 18 |
olle |
137 |
boolean bloodAndSampleItemPrefixesDiffer = Meludi.bloodAndSampleItemPrefixesDiffer(sc.getActiveProjectId()); |
4899 |
10 Jul 18 |
olle |
138 |
if (!bloodAndSampleItemPrefixesDiffer) |
4899 |
10 Jul 18 |
olle |
139 |
{ |
4899 |
10 Jul 18 |
olle |
140 |
bloodList = findAllByCaseNameOldConvention(dc, name); |
4899 |
10 Jul 18 |
olle |
141 |
} |
4899 |
10 Jul 18 |
olle |
142 |
else |
4899 |
10 Jul 18 |
olle |
143 |
{ |
4899 |
10 Jul 18 |
olle |
144 |
bloodList = findAllByCaseNameNewConvention(dc, name); |
4899 |
10 Jul 18 |
olle |
145 |
} |
4899 |
10 Jul 18 |
olle |
146 |
|
4899 |
10 Jul 18 |
olle |
147 |
return bloodList; |
4899 |
10 Jul 18 |
olle |
148 |
} |
4899 |
10 Jul 18 |
olle |
149 |
|
4899 |
10 Jul 18 |
olle |
150 |
/** |
4899 |
10 Jul 18 |
olle |
Find all blood information by case name without filtering on the 'BloodSample' annotation. |
4899 |
10 Jul 18 |
olle |
This method will check for {@link Subtype#BLOOD} samples with a name matching the case name |
4899 |
10 Jul 18 |
olle |
(eg. xxx.b). |
4899 |
10 Jul 18 |
olle |
@since 2.11 |
4899 |
10 Jul 18 |
olle |
155 |
*/ |
4899 |
10 Jul 18 |
olle |
156 |
private static List<Blood> findAllByCaseNameOldConvention(DbControl dc, String name) |
4899 |
10 Jul 18 |
olle |
157 |
{ |
4795 |
08 May 18 |
olle |
// Get rid of suffixes in the name (eg. 'C' which is used for pre-neoadjuvant forms) |
4831 |
05 Jun 18 |
olle |
//if (name.length() > 7) name = name.substring(0, 7); |
4899 |
10 Jul 18 |
olle |
160 |
|
4868 |
25 Jun 18 |
olle |
// Replace sample item prefix with blood item prefix |
4868 |
25 Jun 18 |
olle |
162 |
SessionControl sc = dc.getSessionControl(); |
4868 |
25 Jun 18 |
olle |
163 |
String sampleItemPrefix = Meludi.fetchSampleItemPrefix(sc.getActiveProjectId()); |
4868 |
25 Jun 18 |
olle |
164 |
String bloodItemPrefix = Meludi.fetchBloodItemPrefix(sc.getActiveProjectId()); |
4868 |
25 Jun 18 |
olle |
165 |
if (name.startsWith(sampleItemPrefix)) |
4868 |
25 Jun 18 |
olle |
166 |
{ |
4868 |
25 Jun 18 |
olle |
// Remove sample item prefix |
4868 |
25 Jun 18 |
olle |
168 |
name = name.substring(sampleItemPrefix.length()); |
4868 |
25 Jun 18 |
olle |
// Add blood item prefix |
4868 |
25 Jun 18 |
olle |
170 |
name = bloodItemPrefix + name; |
4868 |
25 Jun 18 |
olle |
171 |
} |
4868 |
25 Jun 18 |
olle |
172 |
|
4795 |
08 May 18 |
olle |
// Look for a blood case with the given name |
4795 |
08 May 18 |
olle |
174 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
175 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
176 |
bloodQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
4795 |
08 May 18 |
olle |
177 |
bloodQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name+".%", Type.STRING))); |
4795 |
08 May 18 |
olle |
178 |
bloodQuery.order(Orders.asc(Hql.property("name"))); |
4795 |
08 May 18 |
olle |
179 |
|
4795 |
08 May 18 |
olle |
180 |
List<Sample> tmp = bloodQuery.list(dc); |
4899 |
10 Jul 18 |
olle |
181 |
List<Blood> bloodList = new ArrayList<Blood>(tmp.size()); |
4795 |
08 May 18 |
olle |
182 |
for (Sample s : tmp) |
4795 |
08 May 18 |
olle |
183 |
{ |
4899 |
10 Jul 18 |
olle |
184 |
bloodList.add(new Blood(s)); |
4795 |
08 May 18 |
olle |
185 |
} |
4899 |
10 Jul 18 |
olle |
186 |
return bloodList; |
4795 |
08 May 18 |
olle |
187 |
} |
4795 |
08 May 18 |
olle |
188 |
|
4795 |
08 May 18 |
olle |
189 |
/** |
4899 |
10 Jul 18 |
olle |
Find all blood information by case name without filtering on the 'BloodSample' annotation. |
4899 |
10 Jul 18 |
olle |
This method will check for {@link Subtype#BLOOD} samples with a CASE_ID annotation equal |
4899 |
10 Jul 18 |
olle |
to the case name. |
4899 |
10 Jul 18 |
olle |
@since 2.11 |
4899 |
10 Jul 18 |
olle |
194 |
*/ |
4899 |
10 Jul 18 |
olle |
195 |
private static List<Blood> findAllByCaseNameNewConvention(DbControl dc, String name) |
4899 |
10 Jul 18 |
olle |
196 |
{ |
4899 |
10 Jul 18 |
olle |
// Look for a blood item with the given case ID as annotation. |
4899 |
10 Jul 18 |
olle |
198 |
String caseId = name; |
4899 |
10 Jul 18 |
olle |
199 |
AnnotationType caseIdType = Annotationtype.CASE_ID.load(dc); |
4899 |
10 Jul 18 |
olle |
200 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4899 |
10 Jul 18 |
olle |
201 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
5468 |
04 Jun 19 |
olle |
202 |
AnnotationRestriction.Options options = new AnnotationRestriction.Options(); |
5468 |
04 Jun 19 |
olle |
203 |
options.setExcludeDefaultValues(false); |
5468 |
04 Jun 19 |
olle |
204 |
options.setIncludeInherited(false); |
5468 |
04 Jun 19 |
olle |
205 |
options.setIncludePrimary(true); |
5468 |
04 Jun 19 |
olle |
//bloodQuery.restrict(new AnnotationSimpleRestriction(null, caseIdType, Operator.EQ, caseId, true, false)); |
5468 |
04 Jun 19 |
olle |
207 |
bloodQuery.restrict(new AnnotationSimpleRestriction(null, caseIdType, Operator.EQ, caseId, options)); |
4899 |
10 Jul 18 |
olle |
208 |
bloodQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
4899 |
10 Jul 18 |
olle |
209 |
bloodQuery.order(Orders.asc(Hql.property("name"))); |
4899 |
10 Jul 18 |
olle |
210 |
|
4899 |
10 Jul 18 |
olle |
211 |
List<Sample> tmp = bloodQuery.list(dc); |
4899 |
10 Jul 18 |
olle |
212 |
List<Blood> bloodList = new ArrayList<Blood>(tmp.size()); |
4899 |
10 Jul 18 |
olle |
213 |
for (Sample s : tmp) |
4899 |
10 Jul 18 |
olle |
214 |
{ |
4899 |
10 Jul 18 |
olle |
215 |
bloodList.add(new Blood(s)); |
4899 |
10 Jul 18 |
olle |
216 |
} |
4899 |
10 Jul 18 |
olle |
217 |
return bloodList; |
4899 |
10 Jul 18 |
olle |
218 |
} |
4899 |
10 Jul 18 |
olle |
219 |
|
4899 |
10 Jul 18 |
olle |
220 |
/** |
4795 |
08 May 18 |
olle |
Find a blood item with the given external ID. |
4795 |
08 May 18 |
olle |
@return A blood item, or null if not found |
4795 |
08 May 18 |
olle |
@since 4.7 |
4795 |
08 May 18 |
olle |
224 |
*/ |
4795 |
08 May 18 |
olle |
225 |
public static Blood findByExternalId(DbControl dc, String externalId) |
4795 |
08 May 18 |
olle |
226 |
{ |
4795 |
08 May 18 |
olle |
227 |
Blood item = null; |
4795 |
08 May 18 |
olle |
228 |
|
4795 |
08 May 18 |
olle |
229 |
ItemQuery<Sample> query = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
230 |
Subtype.BLOOD.addFilter(dc, query); |
4795 |
08 May 18 |
olle |
231 |
query.restrict(Restrictions.eq(Hql.property("externalId"), Expressions.string(externalId))); |
4795 |
08 May 18 |
olle |
232 |
query.order(Orders.desc(Hql.property("name"))); |
4795 |
08 May 18 |
olle |
233 |
query.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT); |
4795 |
08 May 18 |
olle |
234 |
|
4795 |
08 May 18 |
olle |
235 |
List<Sample> items = query.list(dc); |
4795 |
08 May 18 |
olle |
236 |
if (items.size() > 1) |
4795 |
08 May 18 |
olle |
237 |
{ |
4795 |
08 May 18 |
olle |
238 |
throw new InvalidDataException( |
4795 |
08 May 18 |
olle |
239 |
"More than one blood item with the external id '" + externalId + "' was found. " + |
4795 |
08 May 18 |
olle |
240 |
"This wizard can't be used until that is corrected."); |
4795 |
08 May 18 |
olle |
241 |
} |
4795 |
08 May 18 |
olle |
242 |
if (items.size() == 1) |
4795 |
08 May 18 |
olle |
243 |
{ |
4795 |
08 May 18 |
olle |
244 |
item = new Blood(items.get(0)); |
4795 |
08 May 18 |
olle |
245 |
} |
4795 |
08 May 18 |
olle |
246 |
return item; |
4795 |
08 May 18 |
olle |
247 |
} |
4795 |
08 May 18 |
olle |
248 |
|
4795 |
08 May 18 |
olle |
249 |
|
4795 |
08 May 18 |
olle |
250 |
/** |
4795 |
08 May 18 |
olle |
Find all blood information linked with a patient. A patient can have any |
4795 |
08 May 18 |
olle |
number of blood cases. |
4795 |
08 May 18 |
olle |
253 |
*/ |
4795 |
08 May 18 |
olle |
254 |
public static List<Blood> findByPatient(DbControl dc, Patient patient) |
4795 |
08 May 18 |
olle |
255 |
{ |
4795 |
08 May 18 |
olle |
256 |
ItemQuery<Sample> bloodQuery = patient.getBioSource().getSamples(); |
4795 |
08 May 18 |
olle |
257 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
258 |
bloodQuery.include(Include.ALL); |
4795 |
08 May 18 |
olle |
259 |
bloodQuery.order(Orders.asc(Hql.property("name"))); |
4795 |
08 May 18 |
olle |
260 |
List<Sample> tmp = bloodQuery.list(dc); |
4795 |
08 May 18 |
olle |
261 |
List<Blood> blood = new ArrayList<Blood>(tmp.size()); |
4795 |
08 May 18 |
olle |
262 |
for (Sample s : tmp) |
4795 |
08 May 18 |
olle |
263 |
{ |
4795 |
08 May 18 |
olle |
264 |
blood.add(new Blood(s)); |
4795 |
08 May 18 |
olle |
265 |
} |
4795 |
08 May 18 |
olle |
266 |
return blood; |
4795 |
08 May 18 |
olle |
267 |
} |
4795 |
08 May 18 |
olle |
268 |
|
4795 |
08 May 18 |
olle |
269 |
/** |
4795 |
08 May 18 |
olle |
Find blood information by RCCID number. This method will check for |
4795 |
08 May 18 |
olle |
{@link Subtype#BLOOD} samples annotated with BloodRccidNumber=name. |
4795 |
08 May 18 |
olle |
<p> |
4795 |
08 May 18 |
olle |
If exactly one match is found this is the search for blood sample. More than one |
4795 |
08 May 18 |
olle |
match is an error condition. No match indicates an RCCID number that has not yet been |
4795 |
08 May 18 |
olle |
registered (null is returned). |
4795 |
08 May 18 |
olle |
276 |
|
4795 |
08 May 18 |
olle |
@param dc DbControl The DbControl to use to connect to the database. |
4795 |
08 May 18 |
olle |
@param name String The RCCID number to find a blood sample for. |
4795 |
08 May 18 |
olle |
@return Blood A blood item with the input RCCID number, or null if not found. |
4795 |
08 May 18 |
olle |
@since 2.13 |
4795 |
08 May 18 |
olle |
281 |
*/ |
4795 |
08 May 18 |
olle |
282 |
public static Blood findByRccidNumber(DbControl dc, String name) |
4795 |
08 May 18 |
olle |
283 |
{ |
4795 |
08 May 18 |
olle |
284 |
Blood blood = null; |
4795 |
08 May 18 |
olle |
285 |
|
4795 |
08 May 18 |
olle |
// Only follow-up blood samples have non-blank RCCID numbers. |
4795 |
08 May 18 |
olle |
// Return null if input RCCID number is null or empty string. |
4795 |
08 May 18 |
olle |
288 |
if (name == null || name.equals("")) |
4795 |
08 May 18 |
olle |
289 |
{ |
4795 |
08 May 18 |
olle |
290 |
return null; |
4795 |
08 May 18 |
olle |
291 |
} |
4795 |
08 May 18 |
olle |
292 |
|
4795 |
08 May 18 |
olle |
// Look for a blood sample with annotation BloodRccidNumber=name |
4795 |
08 May 18 |
olle |
294 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
295 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
//bloodQuery.restrict(new AnnotationSimpleRestriction(null, Annotationtype.BLOOD_RCCIDNUMBER.load(dc), Operator.EQ, name, true, false)); |
4795 |
08 May 18 |
olle |
297 |
|
4795 |
08 May 18 |
olle |
298 |
List<Sample> bloodSamples = bloodQuery.list(dc); |
4795 |
08 May 18 |
olle |
299 |
|
4795 |
08 May 18 |
olle |
// ...if more than one is found, something is incorrectly registered... abort |
4795 |
08 May 18 |
olle |
301 |
if (bloodSamples.size() > 1) |
4795 |
08 May 18 |
olle |
302 |
{ |
4795 |
08 May 18 |
olle |
303 |
throw new InvalidDataException( |
4795 |
08 May 18 |
olle |
304 |
"Found " + bloodSamples.size() + " blood samples with same RCCID number (" + name + |
4795 |
08 May 18 |
olle |
305 |
"). This wizard can't be used until that is corrected."); |
4795 |
08 May 18 |
olle |
306 |
} |
4795 |
08 May 18 |
olle |
307 |
|
4795 |
08 May 18 |
olle |
308 |
if (bloodSamples.size() == 1) |
4795 |
08 May 18 |
olle |
309 |
{ |
4795 |
08 May 18 |
olle |
310 |
blood = new Blood(bloodSamples.get(0)); |
4795 |
08 May 18 |
olle |
311 |
} |
4795 |
08 May 18 |
olle |
312 |
|
4795 |
08 May 18 |
olle |
313 |
return blood; |
4795 |
08 May 18 |
olle |
314 |
} |
4795 |
08 May 18 |
olle |
315 |
|
4795 |
08 May 18 |
olle |
316 |
/** |
4795 |
08 May 18 |
olle |
Find all blood information by base RCCID number, i.e. the RCCID number disregarding the suffix |
4795 |
08 May 18 |
olle |
letter 'B', 'C', or 'D'. This method will check for {@link Subtype#BLOOD} samples annotated |
4795 |
08 May 18 |
olle |
with BloodRccidNumber=rccidNumber, where rccidNumber is input name string with suffix letter |
4795 |
08 May 18 |
olle |
exchanged for 'B', 'C', and 'D'. |
4795 |
08 May 18 |
olle |
<p> |
4795 |
08 May 18 |
olle |
No match indicates an RCCID number that has not yet been registered (null is returned). |
4795 |
08 May 18 |
olle |
323 |
|
4795 |
08 May 18 |
olle |
@param dc DbControl The DbControl to use to connect to the database. |
4795 |
08 May 18 |
olle |
@param name String The RCCID number to find a blood sample for. |
4795 |
08 May 18 |
olle |
@return Blood A blood item with the input RCCID number, or null if not found. |
4795 |
08 May 18 |
olle |
@since 2.13 |
4795 |
08 May 18 |
olle |
328 |
*/ |
4795 |
08 May 18 |
olle |
329 |
public static List<Blood> findAllByBaseRccidNumber(DbControl dc, String name) |
4795 |
08 May 18 |
olle |
330 |
{ |
4795 |
08 May 18 |
olle |
// Only follow-up blood samples have non-blank RCCID numbers. |
4795 |
08 May 18 |
olle |
// Return null if input RCCID number is null or empty string. |
4795 |
08 May 18 |
olle |
333 |
if (name == null || name.equals("")) |
4795 |
08 May 18 |
olle |
334 |
{ |
4795 |
08 May 18 |
olle |
335 |
return null; |
4795 |
08 May 18 |
olle |
336 |
} |
4795 |
08 May 18 |
olle |
337 |
|
4795 |
08 May 18 |
olle |
// Get base RCCID number (RCCID number without suffix letter 'B', 'C', or 'D') |
4795 |
08 May 18 |
olle |
339 |
String baseRccidNumber = name; |
4795 |
08 May 18 |
olle |
340 |
if (name.endsWith("B") || name.endsWith("C") || name.endsWith("D")) |
4795 |
08 May 18 |
olle |
341 |
{ |
4795 |
08 May 18 |
olle |
// Set base RCCID number as name with last character removed |
4795 |
08 May 18 |
olle |
343 |
baseRccidNumber = name.substring(0, name.length() - 1); |
4795 |
08 May 18 |
olle |
344 |
} |
4795 |
08 May 18 |
olle |
// Check for blood samples with base RCCID number |
4795 |
08 May 18 |
olle |
346 |
List<Blood> bloodSampleList = new ArrayList<Blood>(); |
4795 |
08 May 18 |
olle |
347 |
String rccidNumber = ""; |
4795 |
08 May 18 |
olle |
348 |
for (int i = 0; i < 3; i++) |
4795 |
08 May 18 |
olle |
349 |
{ |
4795 |
08 May 18 |
olle |
350 |
String suffix = "B"; |
4795 |
08 May 18 |
olle |
351 |
if (i == 1) |
4795 |
08 May 18 |
olle |
352 |
{ |
4795 |
08 May 18 |
olle |
353 |
suffix = "C"; |
4795 |
08 May 18 |
olle |
354 |
} |
4795 |
08 May 18 |
olle |
355 |
else if (i == 2) |
4795 |
08 May 18 |
olle |
356 |
{ |
4795 |
08 May 18 |
olle |
357 |
suffix = "D"; |
4795 |
08 May 18 |
olle |
358 |
} |
4795 |
08 May 18 |
olle |
359 |
rccidNumber = baseRccidNumber + suffix; |
4795 |
08 May 18 |
olle |
// Look for a blood sample with annotation BloodRccidNumber=rccidNumber |
4795 |
08 May 18 |
olle |
361 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
362 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
//bloodQuery.restrict(new AnnotationSimpleRestriction(null, Annotationtype.BLOOD_RCCIDNUMBER.load(dc), Operator.EQ, rccidNumber, true, false)); |
4795 |
08 May 18 |
olle |
364 |
|
4795 |
08 May 18 |
olle |
365 |
List<Sample> bloodSamples = bloodQuery.list(dc); |
4795 |
08 May 18 |
olle |
366 |
if (bloodSamples.size() == 1) |
4795 |
08 May 18 |
olle |
367 |
{ |
4795 |
08 May 18 |
olle |
368 |
Blood blood = new Blood(bloodSamples.get(0)); |
4795 |
08 May 18 |
olle |
369 |
bloodSampleList.add(blood); |
4795 |
08 May 18 |
olle |
370 |
} |
4795 |
08 May 18 |
olle |
371 |
} |
4795 |
08 May 18 |
olle |
// Return null if no blood samples were found with input base RCCID number |
4795 |
08 May 18 |
olle |
373 |
if (bloodSampleList.size() == 0) |
4795 |
08 May 18 |
olle |
374 |
{ |
4795 |
08 May 18 |
olle |
375 |
bloodSampleList = null; |
4795 |
08 May 18 |
olle |
376 |
} |
4795 |
08 May 18 |
olle |
377 |
|
4795 |
08 May 18 |
olle |
378 |
return bloodSampleList; |
4795 |
08 May 18 |
olle |
379 |
} |
4795 |
08 May 18 |
olle |
380 |
|
4795 |
08 May 18 |
olle |
381 |
/** |
4795 |
08 May 18 |
olle |
Generate the next auto-generated blood name. This method will search all blood |
4795 |
08 May 18 |
olle |
samples starting with the given prefix and find the one with the highest numeric |
4795 |
08 May 18 |
olle |
suffix. The returned name is the found blood + 1. |
4795 |
08 May 18 |
olle |
@since 2.5 |
4795 |
08 May 18 |
olle |
386 |
*/ |
4795 |
08 May 18 |
olle |
387 |
public static String generateNextName(DbControl dc, String prefix, Subtype subtype) |
4795 |
08 May 18 |
olle |
388 |
{ |
4795 |
08 May 18 |
olle |
389 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
390 |
if (subtype != null) subtype.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
391 |
bloodQuery.restrict(Restrictions.rlike(Hql.property("name"), Expressions.string("^" + prefix + "[0-9]*$"))); |
4795 |
08 May 18 |
olle |
392 |
bloodQuery.order(Orders.desc(Hql.property("name"))); |
4795 |
08 May 18 |
olle |
393 |
bloodQuery.setMaxResults(1); |
4795 |
08 May 18 |
olle |
394 |
bloodQuery.include(Include.ALL); |
4795 |
08 May 18 |
olle |
395 |
List<Sample> blood = bloodQuery.list(dc); |
4795 |
08 May 18 |
olle |
396 |
String name = null; |
4795 |
08 May 18 |
olle |
397 |
if (blood.size() == 0) |
4795 |
08 May 18 |
olle |
398 |
{ |
4795 |
08 May 18 |
olle |
// First blood sample should not have any numeric suffix |
4795 |
08 May 18 |
olle |
400 |
name = prefix; |
4795 |
08 May 18 |
olle |
401 |
} |
4795 |
08 May 18 |
olle |
402 |
else |
4795 |
08 May 18 |
olle |
403 |
{ |
4795 |
08 May 18 |
olle |
404 |
String suffix = blood.get(0).getName().substring(prefix.length()); |
4795 |
08 May 18 |
olle |
405 |
int nextSuffix = Values.getInt(suffix, 1) + 1; |
4795 |
08 May 18 |
olle |
406 |
name = prefix + nextSuffix; |
4795 |
08 May 18 |
olle |
407 |
} |
4795 |
08 May 18 |
olle |
408 |
return name; |
4795 |
08 May 18 |
olle |
409 |
} |
4795 |
08 May 18 |
olle |
410 |
|
4795 |
08 May 18 |
olle |
// Reserve external ids for 5 minutes |
4795 |
08 May 18 |
olle |
412 |
private static final ReservedItems<Integer> RESERVED_EXTERNAL_IDS = new ReservedItems<Integer>(300); |
4795 |
08 May 18 |
olle |
413 |
|
4795 |
08 May 18 |
olle |
414 |
/** |
4795 |
08 May 18 |
olle |
Generate the next auto-generated external ID. This method will search all blood |
4795 |
08 May 18 |
olle |
starting with the given prefix and find the one with the highest numeric suffix. |
4795 |
08 May 18 |
olle |
The returned string is the found blood + 1. This method uses the |
4795 |
08 May 18 |
olle |
{@link ReservedItems} to make sure that the same id is not generated |
4795 |
08 May 18 |
olle |
twice. |
4795 |
08 May 18 |
olle |
@since 4.7 |
4795 |
08 May 18 |
olle |
421 |
*/ |
4795 |
08 May 18 |
olle |
422 |
public static String generateNextExternalId(DbControl dc, String prefix) |
4795 |
08 May 18 |
olle |
423 |
{ |
4795 |
08 May 18 |
olle |
424 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
425 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
426 |
bloodQuery.restrict(Restrictions.rlike(Hql.property("externalId"), Expressions.string("^" + prefix + "[0-9]+$"))); |
4795 |
08 May 18 |
olle |
427 |
bloodQuery.order(Orders.desc(Hql.property("externalId"))); |
4795 |
08 May 18 |
olle |
428 |
bloodQuery.setMaxResults(1); |
4795 |
08 May 18 |
olle |
429 |
bloodQuery.include(Include.ALL); |
4795 |
08 May 18 |
olle |
430 |
List<Sample> blood = bloodQuery.list(dc); |
4795 |
08 May 18 |
olle |
431 |
|
4795 |
08 May 18 |
olle |
432 |
int nextExternalNumber = 1; |
4795 |
08 May 18 |
olle |
433 |
if (blood.size() > 0) |
4795 |
08 May 18 |
olle |
434 |
{ |
4795 |
08 May 18 |
olle |
435 |
String externalNumber = blood.get(0).getExternalId().substring(prefix.length()); |
4795 |
08 May 18 |
olle |
436 |
nextExternalNumber = Integer.parseInt(externalNumber) + 1; |
4795 |
08 May 18 |
olle |
437 |
} |
4795 |
08 May 18 |
olle |
438 |
int maxExternalNumber = 100+nextExternalNumber; |
4795 |
08 May 18 |
olle |
439 |
while (!RESERVED_EXTERNAL_IDS.reserve(nextExternalNumber)) |
4795 |
08 May 18 |
olle |
440 |
{ |
4795 |
08 May 18 |
olle |
441 |
nextExternalNumber++; |
4795 |
08 May 18 |
olle |
442 |
if (nextExternalNumber == maxExternalNumber) |
4795 |
08 May 18 |
olle |
443 |
{ |
4795 |
08 May 18 |
olle |
444 |
throw new RuntimeException("Failed to generate an external ID after 100 tries"); |
4795 |
08 May 18 |
olle |
445 |
} |
4795 |
08 May 18 |
olle |
446 |
} |
4795 |
08 May 18 |
olle |
447 |
String externalId = prefix + MD5.leftPad(Integer.toString(nextExternalNumber), '0', 6); |
4795 |
08 May 18 |
olle |
448 |
return externalId; |
4795 |
08 May 18 |
olle |
449 |
} |
4795 |
08 May 18 |
olle |
450 |
|
4795 |
08 May 18 |
olle |
451 |
/** |
4795 |
08 May 18 |
olle |
Load a blood sample given the exact name of the item. |
4795 |
08 May 18 |
olle |
@since 2.5 |
4795 |
08 May 18 |
olle |
454 |
*/ |
4795 |
08 May 18 |
olle |
455 |
public static Blood getByName(DbControl dc, String name) |
4795 |
08 May 18 |
olle |
456 |
{ |
4795 |
08 May 18 |
olle |
457 |
Blood blood = null; |
4795 |
08 May 18 |
olle |
458 |
|
4795 |
08 May 18 |
olle |
// Look for a blood case with the given name |
4795 |
08 May 18 |
olle |
460 |
ItemQuery<Sample> bloodQuery = Sample.getQuery(); |
4795 |
08 May 18 |
olle |
461 |
Subtype.BLOOD.addFilter(dc, bloodQuery); |
4795 |
08 May 18 |
olle |
462 |
bloodQuery.restrict(Restrictions.eq(Hql.property("name"), Expressions.parameter("name", name, Type.STRING))); |
4795 |
08 May 18 |
olle |
463 |
|
4795 |
08 May 18 |
olle |
464 |
List<Sample> bloodSamples = bloodQuery.list(dc); |
4795 |
08 May 18 |
olle |
465 |
|
4795 |
08 May 18 |
olle |
// ...if more than one is found, something is incorrectly registered... abort |
4795 |
08 May 18 |
olle |
467 |
if (bloodSamples.size() > 1) |
4795 |
08 May 18 |
olle |
468 |
{ |
4795 |
08 May 18 |
olle |
469 |
throw new InvalidDataException( |
4795 |
08 May 18 |
olle |
470 |
"Found " + bloodSamples.size() + " blood samples with the same name (" + name + |
4795 |
08 May 18 |
olle |
471 |
"). This wizard can't be used until that is corrected."); |
4795 |
08 May 18 |
olle |
472 |
} |
4795 |
08 May 18 |
olle |
473 |
|
4795 |
08 May 18 |
olle |
474 |
if (bloodSamples.size() == 1) |
4795 |
08 May 18 |
olle |
475 |
{ |
4795 |
08 May 18 |
olle |
476 |
blood = new Blood(bloodSamples.get(0)); |
4795 |
08 May 18 |
olle |
477 |
} |
4795 |
08 May 18 |
olle |
478 |
|
4795 |
08 May 18 |
olle |
479 |
return blood; |
4795 |
08 May 18 |
olle |
480 |
} |
4795 |
08 May 18 |
olle |
481 |
|
4795 |
08 May 18 |
olle |
482 |
public static Blood getById(DbControl dc, int caseId) |
4795 |
08 May 18 |
olle |
483 |
{ |
4795 |
08 May 18 |
olle |
484 |
Sample s = Sample.getById(dc, caseId); |
4795 |
08 May 18 |
olle |
485 |
return s == null ? null : new Blood(s); |
4795 |
08 May 18 |
olle |
486 |
} |
4795 |
08 May 18 |
olle |
487 |
|
4795 |
08 May 18 |
olle |
488 |
private Blood(Sample sample) |
4795 |
08 May 18 |
olle |
489 |
{ |
4795 |
08 May 18 |
olle |
490 |
super(sample); |
4795 |
08 May 18 |
olle |
491 |
} |
4795 |
08 May 18 |
olle |
492 |
|
4795 |
08 May 18 |
olle |
493 |
|
4795 |
08 May 18 |
olle |
494 |
/** |
4795 |
08 May 18 |
olle |
Get the real sample that represents this case in BASE. |
4795 |
08 May 18 |
olle |
496 |
*/ |
4795 |
08 May 18 |
olle |
497 |
public Sample getSample() |
4795 |
08 May 18 |
olle |
498 |
{ |
4795 |
08 May 18 |
olle |
499 |
return getItem(); |
4795 |
08 May 18 |
olle |
500 |
} |
4831 |
05 Jun 18 |
olle |
501 |
|
4831 |
05 Jun 18 |
olle |
502 |
private JSONObject jsonWell; |
4831 |
05 Jun 18 |
olle |
503 |
|
4831 |
05 Jun 18 |
olle |
504 |
@SuppressWarnings("unchecked") |
4831 |
05 Jun 18 |
olle |
505 |
@Override |
4831 |
05 Jun 18 |
olle |
506 |
protected void initJSON(JSONObject json) |
4831 |
05 Jun 18 |
olle |
507 |
{ |
4831 |
05 Jun 18 |
olle |
508 |
super.initJSON(json); |
4831 |
05 Jun 18 |
olle |
509 |
if (jsonWell != null) json.put("bioWell", jsonWell); |
4831 |
05 Jun 18 |
olle |
510 |
} |
4795 |
08 May 18 |
olle |
511 |
|
4795 |
08 May 18 |
olle |
512 |
/** |
4831 |
05 Jun 18 |
olle |
Load information about the plate and location the current Blood |
4831 |
05 Jun 18 |
olle |
is located on. |
4831 |
05 Jun 18 |
olle |
515 |
*/ |
4831 |
05 Jun 18 |
olle |
516 |
public JSONObject loadBioPlateLocation() |
4831 |
05 Jun 18 |
olle |
517 |
{ |
4831 |
05 Jun 18 |
olle |
518 |
if (jsonWell == null) |
4831 |
05 Jun 18 |
olle |
519 |
{ |
4831 |
05 Jun 18 |
olle |
520 |
jsonWell = JsonUtil.getBioWellAsJSON(getItem().getBioWell(), true); |
4831 |
05 Jun 18 |
olle |
521 |
} |
4831 |
05 Jun 18 |
olle |
522 |
return jsonWell; |
4831 |
05 Jun 18 |
olle |
523 |
} |
4831 |
05 Jun 18 |
olle |
524 |
|
4831 |
05 Jun 18 |
olle |
525 |
/** |
4795 |
08 May 18 |
olle |
Verify that the patient has given their permission to participate in the |
4795 |
08 May 18 |
olle |
study. Due to the order that things get registered, a non-existing "Consent" |
4795 |
08 May 18 |
olle |
annotation is accepted. If the annotation exists the answer must be "Yes", |
4795 |
08 May 18 |
olle |
or an exception is thrown. |
4795 |
08 May 18 |
olle |
530 |
*/ |
4795 |
08 May 18 |
olle |
531 |
public void verifyConsent(DbControl dc, Annotationtype consentType) |
4795 |
08 May 18 |
olle |
532 |
{ |
4795 |
08 May 18 |
olle |
533 |
if (consentType == null) |
4795 |
08 May 18 |
olle |
534 |
{ |
4795 |
08 May 18 |
olle |
535 |
consentType = Annotationtype.CONSENT; |
4795 |
08 May 18 |
olle |
536 |
} |
4795 |
08 May 18 |
olle |
537 |
String consent = (String)consentType.getAnnotationValue(dc, getItem()); |
4795 |
08 May 18 |
olle |
538 |
if (consent != null && !consent.equals("Yes")) |
4795 |
08 May 18 |
olle |
539 |
{ |
4795 |
08 May 18 |
olle |
540 |
throw new PermissionDeniedException("The case (" + getName() + |
4795 |
08 May 18 |
olle |
541 |
") has not agreed to participate in the study."); |
4795 |
08 May 18 |
olle |
542 |
} |
4795 |
08 May 18 |
olle |
543 |
|
4795 |
08 May 18 |
olle |
544 |
} |
4795 |
08 May 18 |
olle |
545 |
|
4795 |
08 May 18 |
olle |
546 |
} |