@sjcrh/proteinpaint-server 2.142.0 → 2.143.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dataset/protected.test.js +1 -2
- package/dataset/termdb.test.js +3 -2
- package/package.json +9 -8
- package/routes/aiProjectAdmin.js +46 -60
- package/routes/aiProjectSelectedWSImages.js +161 -0
- package/routes/brainImaging.js +9 -18
- package/routes/brainImagingSamples.js +2 -4
- package/routes/burden.js +13 -26
- package/routes/correlationVolcano.js +18 -36
- package/routes/dataset.js +6 -12
- package/routes/deleteWSIAnnotation.js +75 -0
- package/routes/dsdata.js +7 -14
- package/routes/dzimages.js +4 -8
- package/routes/gdc.grin2.list.js +13 -26
- package/routes/gdc.grin2.run.js +3 -6
- package/routes/gdc.maf.js +8 -16
- package/routes/gdc.mafBuild.js +14 -28
- package/routes/gene2canonicalisoform.js +4 -8
- package/routes/genelookup.js +2 -4
- package/routes/genesetEnrichment.js +6 -12
- package/routes/genesetOverrepresentation.js +1 -2
- package/routes/genomes.js +1 -2
- package/routes/grin2.js +13 -17
- package/routes/healthcheck.js +3 -6
- package/routes/hicdata.js +4 -8
- package/routes/hicgenome.js +4 -8
- package/routes/hicstat.js +2 -4
- package/routes/img.js +1 -2
- package/routes/isoformlst.js +6 -12
- package/routes/ntseq.js +4 -8
- package/routes/pdomain.js +5 -10
- package/routes/sampledzimages.js +2 -4
- package/routes/samplewsimages.js +3 -67
- package/routes/saveWSIAnnotation.js +100 -0
- package/routes/snp.js +9 -18
- package/routes/termdb.DE.js +23 -46
- package/routes/termdb.boxplot.js +84 -84
- package/routes/termdb.categories.js +9 -18
- package/routes/termdb.cluster.js +23 -46
- package/routes/termdb.cohort.summary.js +3 -6
- package/routes/termdb.cohorts.js +4 -8
- package/routes/termdb.config.js +32 -64
- package/routes/termdb.descrstats.js +6 -12
- package/routes/termdb.filterTermValues.js +4 -8
- package/routes/termdb.numericcategories.js +5 -10
- package/routes/termdb.percentile.js +6 -12
- package/routes/termdb.profileFormScores.js +12 -24
- package/routes/termdb.profileScores.js +7 -14
- package/routes/termdb.rootterm.js +4 -8
- package/routes/termdb.sampleImages.js +4 -8
- package/routes/termdb.singleSampleMutation.js +9 -18
- package/routes/termdb.singlecellDEgenes.js +4 -8
- package/routes/termdb.singlecellData.js +4 -8
- package/routes/termdb.singlecellSamples.js +28 -56
- package/routes/termdb.termchildren.js +5 -10
- package/routes/termdb.termsbyids.js +4 -8
- package/routes/termdb.topMutatedGenes.js +15 -30
- package/routes/termdb.topTermsByType.js +9 -18
- package/routes/termdb.topVariablyExpressedGenes.js +13 -26
- package/routes/termdb.violin.js +124 -135
- package/routes/tileserver.js +14 -15
- package/routes/wsimages.js +42 -46
- package/routes/wsisamples.js +3 -6
- package/src/app.js +4345 -6708
- package/routes/sampleWsiAiApi.js +0 -33
|
@@ -22,23 +22,19 @@ function init({ genomes }) {
|
|
|
22
22
|
const q = req.query;
|
|
23
23
|
try {
|
|
24
24
|
const genome = genomes[q.genome];
|
|
25
|
-
if (!genome)
|
|
26
|
-
throw "invalid genome name";
|
|
25
|
+
if (!genome) throw "invalid genome name";
|
|
27
26
|
const ds = genome.datasets?.[q.dslabel];
|
|
28
|
-
if (!ds)
|
|
29
|
-
throw "invalid ds";
|
|
27
|
+
if (!ds) throw "invalid ds";
|
|
30
28
|
const result = await compute(q, ds);
|
|
31
29
|
res.send(result);
|
|
32
30
|
} catch (e) {
|
|
33
31
|
res.send({ error: e?.message || e });
|
|
34
|
-
if (e instanceof Error && e.stack)
|
|
35
|
-
console.error(e);
|
|
32
|
+
if (e instanceof Error && e.stack) console.error(e);
|
|
36
33
|
}
|
|
37
34
|
};
|
|
38
35
|
}
|
|
39
36
|
async function compute(q, ds) {
|
|
40
|
-
if (!q.featureTw.$id)
|
|
41
|
-
throw "featureTw.$id missing";
|
|
37
|
+
if (!q.featureTw.$id) throw "featureTw.$id missing";
|
|
42
38
|
if (!ds.cohort.correlationVolcano.feature.termTypes.includes(q.featureTw?.term.type))
|
|
43
39
|
throw "unsupported featureTw.term.type";
|
|
44
40
|
const data = await getData(
|
|
@@ -50,22 +46,18 @@ async function compute(q, ds) {
|
|
|
50
46
|
},
|
|
51
47
|
ds
|
|
52
48
|
);
|
|
53
|
-
if (data.error)
|
|
54
|
-
throw data.error;
|
|
49
|
+
if (data.error) throw data.error;
|
|
55
50
|
const vtid2array = /* @__PURE__ */ new Map();
|
|
56
51
|
for (const tw of q.variableTwLst) {
|
|
57
52
|
vtid2array.set(tw.$id, { id: tw.$id, v1: [], v2: [] });
|
|
58
53
|
}
|
|
59
54
|
for (const sid in data.samples) {
|
|
60
55
|
const featureValue = data.samples[sid][q.featureTw.$id]?.value;
|
|
61
|
-
if (!Number.isFinite(featureValue))
|
|
62
|
-
continue;
|
|
56
|
+
if (!Number.isFinite(featureValue)) continue;
|
|
63
57
|
for (const tw of q.variableTwLst) {
|
|
64
|
-
if (!tw.$id)
|
|
65
|
-
throw "variableTwLst[].$id missing";
|
|
58
|
+
if (!tw.$id) throw "variableTwLst[].$id missing";
|
|
66
59
|
const variableValue = data.samples[sid][tw.$id]?.value;
|
|
67
|
-
if (!Number.isFinite(variableValue))
|
|
68
|
-
continue;
|
|
60
|
+
if (!Number.isFinite(variableValue)) continue;
|
|
69
61
|
vtid2array.get(tw.$id).v1.push(featureValue);
|
|
70
62
|
vtid2array.get(tw.$id).v2.push(variableValue);
|
|
71
63
|
}
|
|
@@ -79,8 +71,7 @@ async function compute(q, ds) {
|
|
|
79
71
|
acceptedVariables.push(v);
|
|
80
72
|
}
|
|
81
73
|
const result = { skippedVariables, variableItems: [] };
|
|
82
|
-
if (!acceptedVariables.length)
|
|
83
|
-
return result;
|
|
74
|
+
if (!acceptedVariables.length) return result;
|
|
84
75
|
const input = {
|
|
85
76
|
method: q.correlationMethod || "pearson",
|
|
86
77
|
terms: acceptedVariables
|
|
@@ -105,34 +96,25 @@ async function compute(q, ds) {
|
|
|
105
96
|
}
|
|
106
97
|
function validate_correlationVolcano(ds) {
|
|
107
98
|
const cv = ds.cohort.correlationVolcano;
|
|
108
|
-
if (!cv)
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
throw "cv.feature not obj";
|
|
112
|
-
if (!Array.isArray(cv.feature.termTypes))
|
|
113
|
-
throw "cv.feature.termTypes[] not array";
|
|
99
|
+
if (!cv) return;
|
|
100
|
+
if (typeof cv.feature != "object") throw "cv.feature not obj";
|
|
101
|
+
if (!Array.isArray(cv.feature.termTypes)) throw "cv.feature.termTypes[] not array";
|
|
114
102
|
for (const t of cv.feature.termTypes) {
|
|
115
103
|
if (t == "geneExpression") {
|
|
116
|
-
if (!ds.queries?.geneExpression)
|
|
117
|
-
throw "geneExpression cv.feature is not supported";
|
|
104
|
+
if (!ds.queries?.geneExpression) throw "geneExpression cv.feature is not supported";
|
|
118
105
|
} else if (t == "ssGSEA") {
|
|
119
|
-
if (!ds.queries?.ssGSEA)
|
|
120
|
-
throw "ssGSEA cv.feature is not supported";
|
|
106
|
+
if (!ds.queries?.ssGSEA) throw "ssGSEA cv.feature is not supported";
|
|
121
107
|
} else {
|
|
122
108
|
throw "unknown cv.feature.termType";
|
|
123
109
|
}
|
|
124
110
|
}
|
|
125
|
-
if (typeof cv.variables != "object")
|
|
126
|
-
throw "cv.variables not obj";
|
|
111
|
+
if (typeof cv.variables != "object") throw "cv.variables not obj";
|
|
127
112
|
if (cv.variables.type == "dictionaryTerm") {
|
|
128
|
-
if (!Array.isArray(cv.variables.termIds))
|
|
129
|
-
throw "cv.variables.termIds not array when type=dictionaryTerm";
|
|
113
|
+
if (!Array.isArray(cv.variables.termIds)) throw "cv.variables.termIds not array when type=dictionaryTerm";
|
|
130
114
|
for (const id of cv.variables.termIds) {
|
|
131
115
|
const t = ds.cohort.termdb.q.termjsonByOneid(id);
|
|
132
|
-
if (!t)
|
|
133
|
-
|
|
134
|
-
if (t.type != "integer" && t.type != "float")
|
|
135
|
-
throw "cv.variables.termIds: not integer/float: " + id;
|
|
116
|
+
if (!t) throw "cv.variables.termIds: unknown id: " + id;
|
|
117
|
+
if (t.type != "integer" && t.type != "float") throw "cv.variables.termIds: not integer/float: " + id;
|
|
136
118
|
}
|
|
137
119
|
} else {
|
|
138
120
|
throw "unknown cv.variables.type";
|
package/routes/dataset.js
CHANGED
|
@@ -20,10 +20,8 @@ function init({ genomes }) {
|
|
|
20
20
|
try {
|
|
21
21
|
const q = req.query;
|
|
22
22
|
const genome = genomes[q.genome];
|
|
23
|
-
if (!genome)
|
|
24
|
-
|
|
25
|
-
if (!genome.datasets)
|
|
26
|
-
throw "genomeobj.datasets{} missing";
|
|
23
|
+
if (!genome) throw "unknown genome";
|
|
24
|
+
if (!genome.datasets) throw "genomeobj.datasets{} missing";
|
|
27
25
|
let ds;
|
|
28
26
|
for (const k in genome.datasets) {
|
|
29
27
|
if (k.toLowerCase() == q.dsname.toLowerCase()) {
|
|
@@ -31,8 +29,7 @@ function init({ genomes }) {
|
|
|
31
29
|
break;
|
|
32
30
|
}
|
|
33
31
|
}
|
|
34
|
-
if (!ds)
|
|
35
|
-
throw "invalid dsname";
|
|
32
|
+
if (!ds) throw "invalid dsname";
|
|
36
33
|
const copy = ds.isMds3 ? mds3_init.client_copy(ds) : ds.isMds ? mds_clientcopy(ds) : copy_legacyDataset(ds);
|
|
37
34
|
return res.send({ ds: copy });
|
|
38
35
|
} catch (e) {
|
|
@@ -72,8 +69,7 @@ function mds_clientcopy(ds) {
|
|
|
72
69
|
const toclient = {};
|
|
73
70
|
for (const k in ds.cohort.sampleAttribute.attributes) {
|
|
74
71
|
const a = ds.cohort.sampleAttribute.attributes[k];
|
|
75
|
-
if (!a.clientnoshow)
|
|
76
|
-
toclient[k] = a;
|
|
72
|
+
if (!a.clientnoshow) toclient[k] = a;
|
|
77
73
|
}
|
|
78
74
|
ds2.sampleAttribute = { attributes: toclient };
|
|
79
75
|
}
|
|
@@ -168,8 +164,7 @@ function mds_clientcopy(ds) {
|
|
|
168
164
|
const lst = [];
|
|
169
165
|
if (e.boxplotbysamplegroup.attributes)
|
|
170
166
|
lst.push(e.boxplotbysamplegroup.attributes.map((i) => i.label).join(", "));
|
|
171
|
-
for (const i of e.boxplotbysamplegroup.additionals)
|
|
172
|
-
lst.push(i.label);
|
|
167
|
+
for (const i of e.boxplotbysamplegroup.additionals) lst.push(i.label);
|
|
173
168
|
clientquery.checkexpressionrank.boxplotgroupers = lst;
|
|
174
169
|
}
|
|
175
170
|
}
|
|
@@ -222,8 +217,7 @@ function copy_legacyDataset(ds) {
|
|
|
222
217
|
rep.lst = [];
|
|
223
218
|
for (const e of at.lst) {
|
|
224
219
|
const rep2 = {};
|
|
225
|
-
for (const k2 in e)
|
|
226
|
-
rep2[k2] = e[k2];
|
|
220
|
+
for (const k2 in e) rep2[k2] = e[k2];
|
|
227
221
|
rep.lst.push(rep2);
|
|
228
222
|
}
|
|
229
223
|
} else {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { deleteWSIAnnotationPayload } from "#types/checkers";
|
|
2
|
+
import { getDbConnection } from "#src/aiHistoDBConnection.ts";
|
|
3
|
+
import { runSQL } from "#src/runSQLHelpers.ts";
|
|
4
|
+
const api = {
|
|
5
|
+
endpoint: `deleteWSIAnnotation`,
|
|
6
|
+
methods: {
|
|
7
|
+
delete: {
|
|
8
|
+
...deleteWSIAnnotationPayload,
|
|
9
|
+
init
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
function init({ genomes }) {
|
|
14
|
+
return async (req, res) => {
|
|
15
|
+
try {
|
|
16
|
+
const query = req.query;
|
|
17
|
+
if (!query.genome) throw new Error(".genome is required for deleteWSIAnnotation request.");
|
|
18
|
+
if (!query.dslabel) throw new Error(".dslabel is required for deleteWSIAnnotation request.");
|
|
19
|
+
if (!query.annotation) throw new Error(".annotation:{} is required for deleteWSIAnnotation request.");
|
|
20
|
+
if (!query.projectId) throw new Error(".projectId is required for deleteWSIAnnotation request.");
|
|
21
|
+
if (!query.wsimage) throw new Error(".wsimage is required for deleteWSIAnnotation request.");
|
|
22
|
+
const g = genomes[query.genome];
|
|
23
|
+
if (!g) throw new Error("invalid genome name");
|
|
24
|
+
const ds = g.datasets[query.dslabel];
|
|
25
|
+
if (!ds) throw new Error("invalid dataset name");
|
|
26
|
+
if (typeof ds.queries?.WSImages?.deleteAnnotation === "function") {
|
|
27
|
+
const result = await ds.queries.WSImages.deleteAnnotation(query);
|
|
28
|
+
if (result?.status === "error") {
|
|
29
|
+
return res.status(500).send(result);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
res.status(200).send({ status: `Annotation = ${query.annotation.zoomCoordinates} deleted.` });
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.warn(e);
|
|
35
|
+
res.status(500).send({
|
|
36
|
+
status: "error",
|
|
37
|
+
error: e?.message || String(e)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function validate_query_deleteWSIAnnotation(ds) {
|
|
43
|
+
if (!ds.queries?.WSImages?.db) return;
|
|
44
|
+
const connection = getDbConnection(ds);
|
|
45
|
+
if (!connection) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
validateQuery(ds, connection);
|
|
49
|
+
}
|
|
50
|
+
function validateQuery(ds, connection) {
|
|
51
|
+
ds.queries.WSImages.deleteAnnotation = async (query) => {
|
|
52
|
+
const sql = `
|
|
53
|
+
DELETE FROM project_annotations
|
|
54
|
+
WHERE project_id = ?
|
|
55
|
+
AND coordinates = ?
|
|
56
|
+
AND image_id = (
|
|
57
|
+
SELECT id FROM project_images
|
|
58
|
+
WHERE project_id = ?
|
|
59
|
+
AND image_path = ?
|
|
60
|
+
)
|
|
61
|
+
`;
|
|
62
|
+
const params = [
|
|
63
|
+
query.projectId,
|
|
64
|
+
JSON.stringify(query.annotation.zoomCoordinates),
|
|
65
|
+
query.projectId,
|
|
66
|
+
query.wsimage
|
|
67
|
+
// this is the image_path
|
|
68
|
+
];
|
|
69
|
+
return runSQL(connection, sql, params, "delete annotation");
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
api,
|
|
74
|
+
validate_query_deleteWSIAnnotation
|
|
75
|
+
};
|
package/routes/dsdata.js
CHANGED
|
@@ -24,13 +24,10 @@ function init({ genomes }) {
|
|
|
24
24
|
return async function handle_dsdata(req, res) {
|
|
25
25
|
try {
|
|
26
26
|
const q = req.query;
|
|
27
|
-
if (!genomes[q.genome])
|
|
28
|
-
|
|
29
|
-
if (!q.dsname)
|
|
30
|
-
throw ".dsname missing";
|
|
27
|
+
if (!genomes[q.genome]) throw "invalid genome";
|
|
28
|
+
if (!q.dsname) throw ".dsname missing";
|
|
31
29
|
const ds = genomes[q.genome].datasets[q.dsname];
|
|
32
|
-
if (!ds)
|
|
33
|
-
throw "invalid dsname";
|
|
30
|
+
if (!ds) throw "invalid dsname";
|
|
34
31
|
const data = [];
|
|
35
32
|
for (const query of ds.queries) {
|
|
36
33
|
if (q.expressiononly && !query.isgeneexpression) {
|
|
@@ -56,16 +53,14 @@ function init({ genomes }) {
|
|
|
56
53
|
}
|
|
57
54
|
res.send({ data });
|
|
58
55
|
} catch (e) {
|
|
59
|
-
if (e.stack)
|
|
60
|
-
console.log(e.stack);
|
|
56
|
+
if (e.stack) console.log(e.stack);
|
|
61
57
|
res.send({ error: e.message || e });
|
|
62
58
|
}
|
|
63
59
|
};
|
|
64
60
|
}
|
|
65
61
|
function handle_dsdata_makequery(ds, query, req, genomes) {
|
|
66
62
|
if (req.query.isoform) {
|
|
67
|
-
if (genomes[req.query.genome].genomicNameRegexp.test(req.query.isoform))
|
|
68
|
-
return;
|
|
63
|
+
if (genomes[req.query.genome].genomicNameRegexp.test(req.query.isoform)) return;
|
|
69
64
|
}
|
|
70
65
|
const [sqlstr, values] = query.makequery(req.query);
|
|
71
66
|
if (!sqlstr) {
|
|
@@ -84,8 +79,7 @@ function handle_dsdata_makequery(ds, query, req, genomes) {
|
|
|
84
79
|
result.isgeneexpression = true;
|
|
85
80
|
result.config = query.config;
|
|
86
81
|
for (const q2 of ds.queries) {
|
|
87
|
-
if (!q2.dsblocktracklst)
|
|
88
|
-
continue;
|
|
82
|
+
if (!q2.dsblocktracklst) continue;
|
|
89
83
|
for (const tk of q2.dsblocktracklst) {
|
|
90
84
|
if (tk.type == common.tkt.junction) {
|
|
91
85
|
result.config.dsjunctiontk = tk;
|
|
@@ -109,8 +103,7 @@ function handle_dsdata_vcf(query, req) {
|
|
|
109
103
|
ps.stderr.on("data", (i) => out2.push(i));
|
|
110
104
|
ps.on("close", () => {
|
|
111
105
|
const e = out2.join("").trim();
|
|
112
|
-
if (e != "")
|
|
113
|
-
reject("error querying vcf file");
|
|
106
|
+
if (e != "") reject("error querying vcf file");
|
|
114
107
|
const tmp = out.join("").trim();
|
|
115
108
|
resolve({
|
|
116
109
|
lines: tmp == "" ? [] : tmp.split("\n"),
|
package/routes/dzimages.js
CHANGED
|
@@ -20,16 +20,12 @@ function init({ genomes }) {
|
|
|
20
20
|
try {
|
|
21
21
|
const q = req.query;
|
|
22
22
|
const g = genomes[q.genome];
|
|
23
|
-
if (!g)
|
|
24
|
-
throw "invalid genome name";
|
|
23
|
+
if (!g) throw "invalid genome name";
|
|
25
24
|
const ds = g.datasets[q.dslabel];
|
|
26
|
-
if (!ds)
|
|
27
|
-
throw "invalid dataset name";
|
|
25
|
+
if (!ds) throw "invalid dataset name";
|
|
28
26
|
const sampleId = q.sampleId;
|
|
29
|
-
if (!sampleId)
|
|
30
|
-
|
|
31
|
-
if (illegalpath(req.query.file))
|
|
32
|
-
throw `illegalpath filepath`;
|
|
27
|
+
if (!sampleId) throw "invalid sampleId";
|
|
28
|
+
if (illegalpath(req.query.file)) throw `illegalpath filepath`;
|
|
33
29
|
const filename = path.basename(q.file);
|
|
34
30
|
const allowedExtensions = [".dzi", ".jpeg", ".png"];
|
|
35
31
|
const extension = path.extname(filename);
|
package/routes/gdc.grin2.list.js
CHANGED
|
@@ -24,11 +24,9 @@ function init({ genomes }) {
|
|
|
24
24
|
return async (req, res) => {
|
|
25
25
|
try {
|
|
26
26
|
const g = genomes.hg38;
|
|
27
|
-
if (!g)
|
|
28
|
-
throw "hg38 missing";
|
|
27
|
+
if (!g) throw "hg38 missing";
|
|
29
28
|
const ds = g.datasets?.GDC;
|
|
30
|
-
if (!ds)
|
|
31
|
-
throw "hg38 GDC missing";
|
|
29
|
+
if (!ds) throw "hg38 GDC missing";
|
|
32
30
|
console.log("GRIN2 List Route Received:", JSON.stringify(req.query, null, 2));
|
|
33
31
|
const result = {};
|
|
34
32
|
if (req.query.mafOptions) {
|
|
@@ -49,15 +47,13 @@ function init({ genomes }) {
|
|
|
49
47
|
}
|
|
50
48
|
res.send(result);
|
|
51
49
|
} catch (e) {
|
|
52
|
-
if (e.stack)
|
|
53
|
-
console.log(e.stack);
|
|
50
|
+
if (e.stack) console.log(e.stack);
|
|
54
51
|
res.send({ status: "error", error: e.message || e });
|
|
55
52
|
}
|
|
56
53
|
};
|
|
57
54
|
}
|
|
58
55
|
async function listMafFiles(q, result, ds) {
|
|
59
|
-
if (!q.mafOptions)
|
|
60
|
-
return;
|
|
56
|
+
if (!q.mafOptions) return;
|
|
61
57
|
if (!result.mafFiles) {
|
|
62
58
|
throw new Error("result.mafFiles must be initialized before calling listMafFiles");
|
|
63
59
|
}
|
|
@@ -88,22 +84,17 @@ async function listMafFiles(q, result, ds) {
|
|
|
88
84
|
"cases.samples.tumor_descriptor"
|
|
89
85
|
].join(",")
|
|
90
86
|
};
|
|
91
|
-
if (case_filters.content.length)
|
|
92
|
-
body.case_filters = case_filters;
|
|
87
|
+
if (case_filters.content.length) body.case_filters = case_filters;
|
|
93
88
|
const response = await ky.post(joinUrl(host.rest, "files"), { timeout: false, headers, json: body });
|
|
94
|
-
if (!response.ok)
|
|
95
|
-
throw `HTTP Error: ${response.status} ${response.statusText}`;
|
|
89
|
+
if (!response.ok) throw `HTTP Error: ${response.status} ${response.statusText}`;
|
|
96
90
|
const re = await response.json();
|
|
97
|
-
if (!Number.isInteger(re.data?.pagination?.total))
|
|
98
|
-
|
|
99
|
-
if (!Array.isArray(re.data?.hits))
|
|
100
|
-
throw "re.data.hits[] not array";
|
|
91
|
+
if (!Number.isInteger(re.data?.pagination?.total)) throw "re.data.pagination.total is not int";
|
|
92
|
+
if (!Array.isArray(re.data?.hits)) throw "re.data.hits[] not array";
|
|
101
93
|
const files = [];
|
|
102
94
|
const filteredFiles = [];
|
|
103
95
|
for (const h of re.data.hits) {
|
|
104
96
|
const c = h.cases?.[0];
|
|
105
|
-
if (!c)
|
|
106
|
-
throw "h.cases[0] missing";
|
|
97
|
+
if (!c) throw "h.cases[0] missing";
|
|
107
98
|
if (h.file_size >= maxFileSizeAllowed) {
|
|
108
99
|
filteredFiles.push({
|
|
109
100
|
fileId: h.id,
|
|
@@ -133,8 +124,7 @@ If you want to include it, please increase the maxFileSizeAllowed in the code.`
|
|
|
133
124
|
}
|
|
134
125
|
file.sample_types.push(tumor_descriptor + " " + tissue_type);
|
|
135
126
|
}
|
|
136
|
-
if (normalTypeName)
|
|
137
|
-
file.sample_types.push(normalTypeName);
|
|
127
|
+
if (normalTypeName) file.sample_types.push(normalTypeName);
|
|
138
128
|
}
|
|
139
129
|
file.sample_types = [...new Set(file.sample_types)];
|
|
140
130
|
files.push(file);
|
|
@@ -215,8 +205,7 @@ async function listCnvFiles(q, result, ds) {
|
|
|
215
205
|
}
|
|
216
206
|
}
|
|
217
207
|
};
|
|
218
|
-
if (case_filters.content.length)
|
|
219
|
-
body.case_filters = case_filters;
|
|
208
|
+
if (case_filters.content.length) body.case_filters = case_filters;
|
|
220
209
|
const { host, headers } = ds.getHostHeaders(q);
|
|
221
210
|
try {
|
|
222
211
|
const re = await ky.post(joinUrl(host.rest, "files"), { timeout: false, headers, json: body }).json();
|
|
@@ -232,11 +221,9 @@ async function listCnvFiles(q, result, ds) {
|
|
|
232
221
|
if (h.data_format != "TXT") {
|
|
233
222
|
continue;
|
|
234
223
|
}
|
|
235
|
-
if (!h.analysis?.workflow_type)
|
|
236
|
-
throw "h.analysis.workflow_type missing";
|
|
224
|
+
if (!h.analysis?.workflow_type) throw "h.analysis.workflow_type missing";
|
|
237
225
|
const c = h.cases?.[0];
|
|
238
|
-
if (!c)
|
|
239
|
-
throw "h.cases[0] missing";
|
|
226
|
+
if (!c) throw "h.cases[0] missing";
|
|
240
227
|
if (h.data_type == "Allele-specific Copy Number Segment") {
|
|
241
228
|
} else if (h.data_type == "Masked Copy Number Segment" || h.data_type == "Copy Number Segment" && h.analysis.workflow_type != "DNACopy") {
|
|
242
229
|
const file = {
|
package/routes/gdc.grin2.run.js
CHANGED
|
@@ -34,11 +34,9 @@ function init({ genomes }) {
|
|
|
34
34
|
}
|
|
35
35
|
async function runGrin2(genomes, req, res) {
|
|
36
36
|
const g = genomes.hg38;
|
|
37
|
-
if (!g)
|
|
38
|
-
throw "hg38 missing";
|
|
37
|
+
if (!g) throw "hg38 missing";
|
|
39
38
|
const ds = g.datasets.GDC;
|
|
40
|
-
if (!ds)
|
|
41
|
-
throw "hg38 GDC missing";
|
|
39
|
+
if (!ds) throw "hg38 GDC missing";
|
|
42
40
|
const parsedRequest = req.query;
|
|
43
41
|
const rustInput = {
|
|
44
42
|
caseFiles: parsedRequest.caseFiles,
|
|
@@ -54,8 +52,7 @@ async function runGrin2(genomes, req, res) {
|
|
|
54
52
|
};
|
|
55
53
|
for (const c in g.majorchr) {
|
|
56
54
|
if (ds.queries.singleSampleMutation?.discoPlot?.skipChrM) {
|
|
57
|
-
if (c.toLowerCase() == "chrm")
|
|
58
|
-
continue;
|
|
55
|
+
if (c.toLowerCase() == "chrm") continue;
|
|
59
56
|
}
|
|
60
57
|
rustInput.chromosomes.push(c);
|
|
61
58
|
pyInput.chromosomelist[c] = g.majorchr[c];
|
package/routes/gdc.maf.js
CHANGED
|
@@ -22,11 +22,9 @@ function init({ genomes }) {
|
|
|
22
22
|
return async (req, res) => {
|
|
23
23
|
try {
|
|
24
24
|
const g = genomes.hg38;
|
|
25
|
-
if (!g)
|
|
26
|
-
throw "hg38 missing";
|
|
25
|
+
if (!g) throw "hg38 missing";
|
|
27
26
|
const ds = g.datasets.GDC;
|
|
28
|
-
if (!ds)
|
|
29
|
-
throw "hg38 GDC missing";
|
|
27
|
+
if (!ds) throw "hg38 GDC missing";
|
|
30
28
|
const payload = await listMafFiles(req.query, ds);
|
|
31
29
|
res.send(payload);
|
|
32
30
|
} catch (e) {
|
|
@@ -66,21 +64,16 @@ async function listMafFiles(q, ds) {
|
|
|
66
64
|
"cases.samples.tumor_descriptor"
|
|
67
65
|
].join(",")
|
|
68
66
|
};
|
|
69
|
-
if (case_filters.content.length)
|
|
70
|
-
body.case_filters = case_filters;
|
|
67
|
+
if (case_filters.content.length) body.case_filters = case_filters;
|
|
71
68
|
const response = await ky.post(joinUrl(host.rest, "files"), { timeout: false, json: body });
|
|
72
|
-
if (!response.ok)
|
|
73
|
-
throw `HTTP Error: ${response.status} ${response.statusText}`;
|
|
69
|
+
if (!response.ok) throw `HTTP Error: ${response.status} ${response.statusText}`;
|
|
74
70
|
const re = await response.json();
|
|
75
|
-
if (!Number.isInteger(re.data?.pagination?.total))
|
|
76
|
-
|
|
77
|
-
if (!Array.isArray(re.data?.hits))
|
|
78
|
-
throw "re.data.hits[] not array";
|
|
71
|
+
if (!Number.isInteger(re.data?.pagination?.total)) throw "re.data.pagination.total is not int";
|
|
72
|
+
if (!Array.isArray(re.data?.hits)) throw "re.data.hits[] not array";
|
|
79
73
|
const files = [];
|
|
80
74
|
for (const h of re.data.hits) {
|
|
81
75
|
const c = h.cases?.[0];
|
|
82
|
-
if (!c)
|
|
83
|
-
throw "h.cases[0] missing";
|
|
76
|
+
if (!c) throw "h.cases[0] missing";
|
|
84
77
|
const file = {
|
|
85
78
|
id: h.id,
|
|
86
79
|
project_id: c.project.project_id,
|
|
@@ -98,8 +91,7 @@ async function listMafFiles(q, ds) {
|
|
|
98
91
|
}
|
|
99
92
|
file.sample_types.push(tumor_descriptor + " " + tissue_type);
|
|
100
93
|
}
|
|
101
|
-
if (normalTypeName)
|
|
102
|
-
file.sample_types.push(normalTypeName);
|
|
94
|
+
if (normalTypeName) file.sample_types.push(normalTypeName);
|
|
103
95
|
}
|
|
104
96
|
file.sample_types = [...new Set(file.sample_types)];
|
|
105
97
|
files.push(file);
|
package/routes/gdc.mafBuild.js
CHANGED
|
@@ -22,15 +22,12 @@ function init({ genomes }) {
|
|
|
22
22
|
try {
|
|
23
23
|
const q = req.query;
|
|
24
24
|
const g = genomes.hg38;
|
|
25
|
-
if (!g)
|
|
26
|
-
throw "hg38 missing";
|
|
25
|
+
if (!g) throw "hg38 missing";
|
|
27
26
|
const ds = g.datasets.GDC;
|
|
28
|
-
if (!ds)
|
|
29
|
-
throw "hg38 GDC missing";
|
|
27
|
+
if (!ds) throw "hg38 GDC missing";
|
|
30
28
|
await buildMaf(q, res, ds);
|
|
31
29
|
} catch (e) {
|
|
32
|
-
if (e.stack)
|
|
33
|
-
console.log(e.stack);
|
|
30
|
+
if (e.stack) console.log(e.stack);
|
|
34
31
|
res.send({ status: "error", error: e.message || e });
|
|
35
32
|
}
|
|
36
33
|
};
|
|
@@ -57,8 +54,7 @@ async function buildMaf(q, res, ds) {
|
|
|
57
54
|
if (streams) {
|
|
58
55
|
const { rustStream, endStream } = streams;
|
|
59
56
|
res.on("close", () => {
|
|
60
|
-
if (res.writableEnded)
|
|
61
|
-
return;
|
|
57
|
+
if (res.writableEnded) return;
|
|
62
58
|
try {
|
|
63
59
|
console.log("\n-- forced res.end() ---\n");
|
|
64
60
|
res.end();
|
|
@@ -74,8 +70,7 @@ async function buildMaf(q, res, ds) {
|
|
|
74
70
|
rustStream.pipe(res, { end: false }).on("error", (e) => {
|
|
75
71
|
console.log("rustStream.pipe().on(error)", e);
|
|
76
72
|
}).on("end", () => {
|
|
77
|
-
if (res.writableEnded)
|
|
78
|
-
return;
|
|
73
|
+
if (res.writableEnded) return;
|
|
79
74
|
console.log("rustStream.on(end), trigger res.end()");
|
|
80
75
|
res.end();
|
|
81
76
|
});
|
|
@@ -86,8 +81,7 @@ async function buildMaf(q, res, ds) {
|
|
|
86
81
|
console.log("error calling stream_rust(gdcmaf)", e);
|
|
87
82
|
}
|
|
88
83
|
function emitJson(data, end = true) {
|
|
89
|
-
if (res.writableEnded)
|
|
90
|
-
return;
|
|
84
|
+
if (res.writableEnded) return;
|
|
91
85
|
if (data) {
|
|
92
86
|
res.write(`\r
|
|
93
87
|
--${boundary}`);
|
|
@@ -100,13 +94,11 @@ async function buildMaf(q, res, ds) {
|
|
|
100
94
|
--${boundary}--\r
|
|
101
95
|
`);
|
|
102
96
|
mayLog("rust gdcmaf", Date.now() - t0);
|
|
103
|
-
if (end)
|
|
104
|
-
res.end();
|
|
97
|
+
if (end) res.end();
|
|
105
98
|
}
|
|
106
99
|
}
|
|
107
100
|
async function getFileLstUnderSizeLimit(lst, host) {
|
|
108
|
-
if (lst.length == 0)
|
|
109
|
-
throw "fileIdLst[] not array or blank";
|
|
101
|
+
if (lst.length == 0) throw "fileIdLst[] not array or blank";
|
|
110
102
|
const body = {
|
|
111
103
|
filters: {
|
|
112
104
|
op: "in",
|
|
@@ -116,25 +108,19 @@ async function getFileLstUnderSizeLimit(lst, host) {
|
|
|
116
108
|
fields: "file_size"
|
|
117
109
|
};
|
|
118
110
|
const response = await ky.post(joinUrl(host.rest, "files"), { timeout: false, json: body });
|
|
119
|
-
if (!response.ok)
|
|
120
|
-
throw `HTTP Error: ${response.status} ${response.statusText}`;
|
|
111
|
+
if (!response.ok) throw `HTTP Error: ${response.status} ${response.statusText}`;
|
|
121
112
|
const re = await response.json();
|
|
122
|
-
if (!Array.isArray(re.data?.hits))
|
|
123
|
-
throw "re.data.hits[] not array";
|
|
113
|
+
if (!Array.isArray(re.data?.hits)) throw "re.data.hits[] not array";
|
|
124
114
|
const out = [];
|
|
125
115
|
let cumsize = 0;
|
|
126
116
|
for (const h of re.data.hits) {
|
|
127
|
-
if (cumsize >= maxTotalSizeCompressed)
|
|
128
|
-
|
|
129
|
-
if (!h.
|
|
130
|
-
throw ".id missing";
|
|
131
|
-
if (!Number.isInteger(h.file_size))
|
|
132
|
-
throw ".file_size not integer";
|
|
117
|
+
if (cumsize >= maxTotalSizeCompressed) break;
|
|
118
|
+
if (!h.id) throw ".id missing";
|
|
119
|
+
if (!Number.isInteger(h.file_size)) throw ".file_size not integer";
|
|
133
120
|
cumsize += h.file_size;
|
|
134
121
|
out.push(h.id);
|
|
135
122
|
}
|
|
136
|
-
if (out.length == 0)
|
|
137
|
-
throw "no file available";
|
|
123
|
+
if (out.length == 0) throw "no file available";
|
|
138
124
|
return out;
|
|
139
125
|
}
|
|
140
126
|
export {
|
|
@@ -20,19 +20,15 @@ const api = {
|
|
|
20
20
|
function init({ genomes }) {
|
|
21
21
|
return function(req, res) {
|
|
22
22
|
try {
|
|
23
|
-
if (!req.query.gene)
|
|
24
|
-
throw ".gene missing";
|
|
23
|
+
if (!req.query.gene) throw ".gene missing";
|
|
25
24
|
const genome = genomes[req.query.genome];
|
|
26
|
-
if (!genome)
|
|
27
|
-
|
|
28
|
-
if (!genome.genedb.get_gene2canonicalisoform)
|
|
29
|
-
throw "gene2canonicalisoform not supported on this genome";
|
|
25
|
+
if (!genome) throw "unknown genome";
|
|
26
|
+
if (!genome.genedb.get_gene2canonicalisoform) throw "gene2canonicalisoform not supported on this genome";
|
|
30
27
|
const data = genome.genedb.get_gene2canonicalisoform.get(req.query.gene);
|
|
31
28
|
res.send(data);
|
|
32
29
|
} catch (e) {
|
|
33
30
|
res.send({ error: e.message || e });
|
|
34
|
-
if (e.stack)
|
|
35
|
-
console.log(e.stack);
|
|
31
|
+
if (e.stack) console.log(e.stack);
|
|
36
32
|
}
|
|
37
33
|
};
|
|
38
34
|
}
|
package/routes/genelookup.js
CHANGED
|
@@ -18,14 +18,12 @@ function init({ genomes }) {
|
|
|
18
18
|
try {
|
|
19
19
|
const q = req.query;
|
|
20
20
|
const g = genomes[q.genome];
|
|
21
|
-
if (!g)
|
|
22
|
-
throw "invalid genome name";
|
|
21
|
+
if (!g) throw "invalid genome name";
|
|
23
22
|
const result = getResult(g, q);
|
|
24
23
|
res.send(result);
|
|
25
24
|
} catch (e) {
|
|
26
25
|
res.send({ error: e.message || e });
|
|
27
|
-
if (e.stack)
|
|
28
|
-
console.log(e.stack);
|
|
26
|
+
if (e.stack) console.log(e.stack);
|
|
29
27
|
}
|
|
30
28
|
};
|
|
31
29
|
}
|
|
@@ -26,13 +26,11 @@ function init({ genomes }) {
|
|
|
26
26
|
const q = req.query;
|
|
27
27
|
const results = await run_genesetEnrichment_analysis(q, genomes);
|
|
28
28
|
if (!q.geneset_name) {
|
|
29
|
-
if (typeof results != "object")
|
|
30
|
-
throw "gsea result is not object";
|
|
29
|
+
if (typeof results != "object") throw "gsea result is not object";
|
|
31
30
|
res.send(results);
|
|
32
31
|
return;
|
|
33
32
|
}
|
|
34
|
-
if (typeof results != "string")
|
|
35
|
-
throw "gsea result is not string";
|
|
33
|
+
if (typeof results != "string") throw "gsea result is not string";
|
|
36
34
|
res.sendFile(results, (err) => {
|
|
37
35
|
fs.unlink(results, () => {
|
|
38
36
|
});
|
|
@@ -42,14 +40,12 @@ function init({ genomes }) {
|
|
|
42
40
|
});
|
|
43
41
|
} catch (e) {
|
|
44
42
|
res.send({ status: "error", error: e.message || e });
|
|
45
|
-
if (e.stack)
|
|
46
|
-
console.log(e.stack);
|
|
43
|
+
if (e.stack) console.log(e.stack);
|
|
47
44
|
}
|
|
48
45
|
};
|
|
49
46
|
}
|
|
50
47
|
async function run_genesetEnrichment_analysis(q, genomes) {
|
|
51
|
-
if (!genomes[q.genome].termdbs)
|
|
52
|
-
throw "termdb database is not available for " + q.genome;
|
|
48
|
+
if (!genomes[q.genome].termdbs) throw "termdb database is not available for " + q.genome;
|
|
53
49
|
const genesetenrichment_input = {
|
|
54
50
|
genes: q.genes,
|
|
55
51
|
fold_change: q.fold_change,
|
|
@@ -82,11 +78,9 @@ async function run_genesetEnrichment_analysis(q, genomes) {
|
|
|
82
78
|
mayLog(line);
|
|
83
79
|
}
|
|
84
80
|
}
|
|
85
|
-
if (data_found)
|
|
86
|
-
return result;
|
|
81
|
+
if (data_found) return result;
|
|
87
82
|
const image_file_name = path.join(cachedir_gsea, result.image_file);
|
|
88
|
-
if (image_found)
|
|
89
|
-
return image_file_name;
|
|
83
|
+
if (image_found) return image_file_name;
|
|
90
84
|
throw "data or image not found in gsea output; this should not happen";
|
|
91
85
|
} else if (q.method == "cerno") {
|
|
92
86
|
const time1 = (/* @__PURE__ */ new Date()).valueOf();
|
|
@@ -26,8 +26,7 @@ function init({ genomes }) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
async function run_genesetOverrepresentation_analysis(q, genomes) {
|
|
29
|
-
if (!genomes[q.genome].termdbs)
|
|
30
|
-
throw "termdb database is not available for " + q.genome;
|
|
29
|
+
if (!genomes[q.genome].termdbs) throw "termdb database is not available for " + q.genome;
|
|
31
30
|
const gene_overrepresentation_input_type = {
|
|
32
31
|
sample_genes: q.sample_genes,
|
|
33
32
|
msigdb: genomes[q.genome].termdbs.msigdb.cohort.db.connection.name,
|