@sjcrh/proteinpaint-server 2.44.0 → 2.46.1
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/clinvar.hg19.js +53 -52
- package/dataset/clinvar.hg38.js +74 -73
- package/dataset/clinvar.js +164 -47
- package/dataset/termdb.test.js +257 -0
- package/genome/CriGri.js +1859 -27
- package/genome/cgc.js +743 -7
- package/genome/danRer10.js +1108 -46
- package/genome/dm3.js +71 -44
- package/genome/dm6.js +1926 -45
- package/genome/galGal5.js +23522 -46
- package/genome/galGal6.js +512 -46
- package/genome/hg19.js +293 -198
- package/genome/hg38.js +472 -105
- package/genome/hg38.test.js +406 -40
- package/genome/hgvirus.js +45 -20
- package/genome/mm10.js +135 -67
- package/genome/mm9.js +116 -79
- package/genome/rn6.js +1002 -47
- package/package.json +31 -35
- package/routes/_template_.js +30 -0
- package/routes/burden.js +149 -0
- package/routes/dataset.js +266 -0
- package/routes/dsdata.js +127 -0
- package/routes/gdc.maf.js +120 -0
- package/routes/gdc.mafBuild.js +106 -0
- package/routes/gdc.topMutatedGenes.js +465 -0
- package/routes/gene2canonicalisoform.js +41 -0
- package/routes/genelookup.js +52 -0
- package/routes/genomes.js +144 -0
- package/routes/healthcheck.js +30 -0
- package/routes/hicdata.js +98 -0
- package/routes/hicstat.js +55 -0
- package/routes/isoformlst.js +57 -0
- package/routes/ntseq.js +43 -0
- package/routes/pdomain.js +61 -0
- package/routes/snp.js +107 -0
- package/routes/termdb.categories.js +209 -0
- package/routes/termdb.cluster.js +228 -0
- package/routes/termdb.cohort.summary.js +38 -0
- package/routes/termdb.cohorts.js +49 -0
- package/routes/termdb.config.js +202 -0
- package/routes/termdb.getdescrstats.js +102 -0
- package/routes/termdb.getnumericcategories.js +92 -0
- package/routes/termdb.getpercentile.js +108 -0
- package/routes/termdb.getrootterm.js +65 -0
- package/routes/termdb.gettermchildren.js +67 -0
- package/routes/termdb.singleSampleMutation.js +80 -0
- package/routes/termdb.singlecellData.js +46 -0
- package/routes/termdb.singlecellSamples.js +160 -0
- package/routes/termdb.termsbyids.js +59 -0
- package/routes/termdb.topVariablyExpressedGenes.js +171 -0
- package/routes/termdb.violin.js +77 -0
- package/src/app.js +41500 -0
- package/src/serverconfig.js +14 -8
- package/start.js +3 -3
- package/routes/README.md +0 -84
- package/routes/burden.ts +0 -143
- package/routes/gdc.maf.ts +0 -195
- package/routes/gdc.mafBuild.ts +0 -114
- package/routes/gdc.topMutatedGenes.ts +0 -586
- package/routes/genelookup.ts +0 -50
- package/routes/healthcheck.ts +0 -29
- package/routes/hicdata.ts +0 -111
- package/routes/hicstat.ts +0 -55
- package/routes/termdb.categories.ts +0 -245
- package/routes/termdb.cluster.ts +0 -248
- package/routes/termdb.getdescrstats.ts +0 -102
- package/routes/termdb.getnumericcategories.ts +0 -99
- package/routes/termdb.getpercentile.ts +0 -118
- package/routes/termdb.getrootterm.ts +0 -73
- package/routes/termdb.gettermchildren.ts +0 -82
- package/routes/termdb.singleSampleMutation.ts +0 -87
- package/routes/termdb.singlecellData.ts +0 -49
- package/routes/termdb.singlecellSamples.ts +0 -175
- package/routes/termdb.termsbyids.ts +0 -63
- package/routes/termdb.topVariablyExpressedGenes.ts +0 -214
- package/routes/termdb.violin.ts +0 -77
- package/server.js +0 -2
- package/server.js.map +0 -1
- package/shared/common.js +0 -1080
- package/shared/termdb.initbinconfig.js +0 -96
- package/shared/vcf.js +0 -629
package/package.json
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjcrh/proteinpaint-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.46.1",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
|
|
5
|
-
"main": "
|
|
6
|
+
"main": "src/app.js",
|
|
7
|
+
"module": "src/app.js",
|
|
6
8
|
"bin": "start.js",
|
|
7
9
|
"imports": {
|
|
8
|
-
"#
|
|
10
|
+
"#types": "./shared/types/index.ts",
|
|
9
11
|
"#shared/types/*": "./shared/types/*",
|
|
12
|
+
"#shared/*": "./shared/*",
|
|
10
13
|
"#src/*": "./src/*",
|
|
11
14
|
"#routes/*": "./routes/*"
|
|
12
15
|
},
|
|
13
16
|
"scripts": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"start": "
|
|
17
|
+
"dev": "npm run start",
|
|
18
|
+
"prestart": "tsx emitImports.js dev > server.js",
|
|
19
|
+
"start": "tsx watch src/app.ts",
|
|
20
|
+
"test:unit": "tsx emitImports.js unit > serverTests.js && tsx serverTests.js && rm -rf ./cache",
|
|
21
|
+
"getconf": "../build/getConfigProp.js",
|
|
22
|
+
"doc": "../augen/build.sh routes shared/types/routes shared/checkers ../public/docs/server",
|
|
23
|
+
"mjs": "esbuild \"$DIR/*.ts\" --platform=node --outdir=\"$DIR\" --format=esm",
|
|
24
|
+
"cjs": "esbuild \"$DIR/*.ts\" --platform=node --outdir=\"$DIR\" --format=cjs",
|
|
25
|
+
"build": "./build.sh",
|
|
26
|
+
"prepack": "npm run build",
|
|
27
|
+
"postpack": "./dedupjs.sh",
|
|
28
|
+
"dedup": "./dedupjs.sh",
|
|
29
|
+
"//todo": "refactor or deprecate the scripts below",
|
|
17
30
|
"pretest": "tsc --esModuleInterop genome/*.ts dataset/*.ts && ./test/pretest.js",
|
|
18
|
-
"
|
|
19
|
-
"precheckers": "tsc --esModuleInterop genome/*.ts dataset/*.ts",
|
|
20
|
-
"checkers": "webpack --config=./test/webpack.config.js && node test/emitPrepFiles.bundle.js && typia generate --input shared/checkers-raw --output shared/checkers",
|
|
31
|
+
"prepare": "ts-patch install",
|
|
21
32
|
"pretest:type": "npm run checkers",
|
|
22
|
-
"test:type": "webpack --env NODE_ENV=test exportsFilename=type-test-context.js && node --enable-source-maps test/serverTests.js",
|
|
23
|
-
"pretest:unit": "npm run precheckers",
|
|
24
|
-
"test:unit": "webpack --env NODE_ENV=test exportsFilename=unit-test-context.js && node --enable-source-maps test/serverTests.js",
|
|
25
33
|
"pretest:integration": "tsc --esModuleInterop genome/*.ts dataset/*.ts",
|
|
26
34
|
"test:integration": "echo 'TODO: server integration tests'",
|
|
27
|
-
"
|
|
28
|
-
"test:tsc": "tsc --esModuleInterop --noEmit --allowImportingTsExtensions ./shared/types/test/*.type.spec.ts",
|
|
29
|
-
"response": "nodemon modules/test/test.server.js --watch src",
|
|
30
|
-
"getconf": "../build/getConfigProp.js",
|
|
31
|
-
"doc": "../augen/build.sh routes shared/types/routes shared/checkers ../public/docs/server"
|
|
35
|
+
"test:tsc": "tsc --esModuleInterop --noEmit --allowImportingTsExtensions ./shared/types/test/*.type.spec.ts"
|
|
32
36
|
},
|
|
33
37
|
"author": "",
|
|
34
38
|
"license": "SEE LICENSE IN ./LICENSE",
|
|
@@ -39,8 +43,11 @@
|
|
|
39
43
|
"@babel/preset-env": "^7.9.6",
|
|
40
44
|
"@babel/preset-typescript": "^7.21.4",
|
|
41
45
|
"@babel/register": "^7.14.5",
|
|
46
|
+
"@types/node": "^20.11.24",
|
|
42
47
|
"@typescript-eslint/eslint-plugin": "^5.60.0",
|
|
43
48
|
"babel-loader": "^8.2.2",
|
|
49
|
+
"esbuild": "^0.19.12",
|
|
50
|
+
"glob": "^7.2.3",
|
|
44
51
|
"node-watch": "^0.7.1",
|
|
45
52
|
"nodemon": "^2.0.19",
|
|
46
53
|
"prettier": "^2.8.8",
|
|
@@ -50,14 +57,10 @@
|
|
|
50
57
|
"tsx": "^4.7.1",
|
|
51
58
|
"typedoc": "^0.24.8",
|
|
52
59
|
"typescript": "^5.0.3",
|
|
53
|
-
"typia": "^4.1.14"
|
|
54
|
-
"webpack": "^5.76.0",
|
|
55
|
-
"webpack-cli": "^4.9.2",
|
|
56
|
-
"webpack-node-externals": "^3.0.0",
|
|
57
|
-
"webpack-notifier": "^1.15.0"
|
|
60
|
+
"typia": "^4.1.14"
|
|
58
61
|
},
|
|
59
62
|
"dependencies": {
|
|
60
|
-
"@sjcrh/augen": "2.
|
|
63
|
+
"@sjcrh/augen": "2.46.0",
|
|
61
64
|
"@sjcrh/proteinpaint-rust": "2.44.0",
|
|
62
65
|
"better-sqlite3": "^9.4.1",
|
|
63
66
|
"body-parser": "^1.15.2",
|
|
@@ -68,7 +71,7 @@
|
|
|
68
71
|
"deep-object-diff": "^1.1.0",
|
|
69
72
|
"express": "^4.17.1",
|
|
70
73
|
"express-basic-auth": "^1.1.5",
|
|
71
|
-
"got": "^
|
|
74
|
+
"got": "^14.2.0",
|
|
72
75
|
"image-size": "^0.5.5",
|
|
73
76
|
"jsonwebtoken": "^9.0.0",
|
|
74
77
|
"jstat": "^1.9.3",
|
|
@@ -88,24 +91,17 @@
|
|
|
88
91
|
},
|
|
89
92
|
"files": [
|
|
90
93
|
"bin.js",
|
|
91
|
-
"dataset
|
|
92
|
-
"dataset/gdc*.js",
|
|
94
|
+
"dataset/*.js",
|
|
93
95
|
"genome/*.js",
|
|
96
|
+
"routes/*.js",
|
|
97
|
+
"start.js",
|
|
98
|
+
"src/app.js",
|
|
94
99
|
"src/serverconfig.js",
|
|
95
100
|
"src/lines2R.js",
|
|
96
101
|
"src/mds3.gdc.filter.js",
|
|
97
102
|
"src/checkReadingFrame.js",
|
|
98
103
|
"src/bedj.parseBed.js",
|
|
99
|
-
"routes/*",
|
|
100
|
-
"cards/*",
|
|
101
|
-
"server.js*",
|
|
102
|
-
"start.js",
|
|
103
|
-
"shared/common.js",
|
|
104
|
-
"shared/termdb.initbinconfig.js",
|
|
105
|
-
"shared/vcf.js",
|
|
106
104
|
"utils/*.R",
|
|
107
|
-
"utils/rust/*.*",
|
|
108
|
-
"utils/rust/src",
|
|
109
105
|
"LICENSE/*"
|
|
110
106
|
],
|
|
111
107
|
"bugs": {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const api = {
|
|
2
|
+
// route endpoint
|
|
3
|
+
// - no need for trailing slash
|
|
4
|
+
// - should be a noun (method is based on HTTP GET, POST, etc)
|
|
5
|
+
// - don't add 'Data' as response is assumed to be data
|
|
6
|
+
endpoint: "...",
|
|
7
|
+
methods: {
|
|
8
|
+
get: {
|
|
9
|
+
init,
|
|
10
|
+
request: {
|
|
11
|
+
typeId: "any"
|
|
12
|
+
},
|
|
13
|
+
response: {
|
|
14
|
+
typeId: "any"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
post: {
|
|
18
|
+
alternativeFor: "get",
|
|
19
|
+
init
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function init({ genomes }) {
|
|
24
|
+
return async function(req, res) {
|
|
25
|
+
console.log(genomes, req, res);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
api
|
|
30
|
+
};
|
package/routes/burden.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import lines2R from "#src/lines2R.js";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import serverconfig from "#src/serverconfig.js";
|
|
4
|
+
import { write_file } from "#src/utils.js";
|
|
5
|
+
const api = {
|
|
6
|
+
endpoint: "burden",
|
|
7
|
+
methods: {
|
|
8
|
+
get: {
|
|
9
|
+
init({ genomes }) {
|
|
10
|
+
return async (req, res) => {
|
|
11
|
+
try {
|
|
12
|
+
const genome = genomes[req.query.genome];
|
|
13
|
+
if (!genome)
|
|
14
|
+
throw `invalid q.genome=${req.query.genome}`;
|
|
15
|
+
const q = req.query;
|
|
16
|
+
const ds = genome.datasets[q.dslabel];
|
|
17
|
+
if (!ds)
|
|
18
|
+
throw `invalid q.genome=${req.query.dslabel}`;
|
|
19
|
+
if (!ds.cohort.cumburden?.files)
|
|
20
|
+
throw `missing ds.cohort.cumburden.files`;
|
|
21
|
+
const estimates = await getBurdenEstimates(req, ds);
|
|
22
|
+
const { keys, rows } = formatPayload(estimates);
|
|
23
|
+
res.send({ status: "ok", keys, rows });
|
|
24
|
+
} catch (e) {
|
|
25
|
+
res.send({ status: "error", error: e.message || e });
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
request: {
|
|
30
|
+
typeId: "BurdenRequest"
|
|
31
|
+
},
|
|
32
|
+
response: {
|
|
33
|
+
typeId: "BurdenResponse"
|
|
34
|
+
},
|
|
35
|
+
examples: [
|
|
36
|
+
{
|
|
37
|
+
request: {
|
|
38
|
+
body: {
|
|
39
|
+
genome: "hg38",
|
|
40
|
+
// TODO: !!! use hg38-test and TermdbTest !!!
|
|
41
|
+
dslabel: "SJLife",
|
|
42
|
+
diaggrp: 5,
|
|
43
|
+
sex: 1,
|
|
44
|
+
white: 1,
|
|
45
|
+
agedx: 1,
|
|
46
|
+
bleo: 0,
|
|
47
|
+
etop: 0,
|
|
48
|
+
cisp: 0,
|
|
49
|
+
carbo: 0,
|
|
50
|
+
steriod: 0,
|
|
51
|
+
vcr: 0,
|
|
52
|
+
hdmtx: 0,
|
|
53
|
+
itmt: 0,
|
|
54
|
+
ced: 0,
|
|
55
|
+
dox: 0,
|
|
56
|
+
heart: 0,
|
|
57
|
+
brain: 0,
|
|
58
|
+
abd: 0,
|
|
59
|
+
pelvis: 0,
|
|
60
|
+
chest: 0
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
response: {
|
|
64
|
+
header: { status: 200 }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
async function getBurdenEstimates(q, ds) {
|
|
72
|
+
const infile = path.join(serverconfig.cachedir, Math.random().toString() + ".json");
|
|
73
|
+
for (const k in q.query) {
|
|
74
|
+
q.query[k] = Number(q.query[k]);
|
|
75
|
+
}
|
|
76
|
+
const data = Object.assign({}, defaults, q.query);
|
|
77
|
+
await write_file(infile, JSON.stringify(data));
|
|
78
|
+
const { fit, surv, sample } = ds.cohort.cumburden.files;
|
|
79
|
+
if (!fit || !surv || !sample)
|
|
80
|
+
throw `missing one or more of ds.cohort.burden.files.{fit, surv, sample}`;
|
|
81
|
+
const args = [
|
|
82
|
+
infile,
|
|
83
|
+
`${serverconfig.tpmasterdir}/${fit}`,
|
|
84
|
+
`${serverconfig.tpmasterdir}/${surv}`,
|
|
85
|
+
`${serverconfig.tpmasterdir}/${sample}`
|
|
86
|
+
];
|
|
87
|
+
const Routput = await lines2R(path.join(serverconfig.binpath, "utils/burden.R"), [], args);
|
|
88
|
+
const estimates = JSON.parse(Routput[0]);
|
|
89
|
+
return estimates;
|
|
90
|
+
}
|
|
91
|
+
function formatPayload(estimates) {
|
|
92
|
+
const rawKeys = Object.keys(estimates[0]);
|
|
93
|
+
const outKeys = [];
|
|
94
|
+
const keys = [];
|
|
95
|
+
for (const k of rawKeys) {
|
|
96
|
+
if (k == "chc") {
|
|
97
|
+
keys.push(k);
|
|
98
|
+
outKeys.push(k);
|
|
99
|
+
} else {
|
|
100
|
+
const age = Number(k.slice(1).split(",")[0]);
|
|
101
|
+
if (age <= 60 && age % 2 == 0) {
|
|
102
|
+
keys.push(k);
|
|
103
|
+
outKeys.push(`burden${age}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const rows = [];
|
|
108
|
+
for (const v of estimates) {
|
|
109
|
+
rows.push(keys.map((k) => v[k]));
|
|
110
|
+
}
|
|
111
|
+
return { keys: outKeys, rows };
|
|
112
|
+
}
|
|
113
|
+
const defaults = Object.freeze({
|
|
114
|
+
diaggrp: 5,
|
|
115
|
+
sex: 0,
|
|
116
|
+
white: 1,
|
|
117
|
+
agedx: 1,
|
|
118
|
+
// chemotherapy
|
|
119
|
+
steriod: 0,
|
|
120
|
+
bleo: 0,
|
|
121
|
+
vcr: 0,
|
|
122
|
+
//12, // Vincristine
|
|
123
|
+
etop: 0,
|
|
124
|
+
//2500, // Etoposide
|
|
125
|
+
itmt: 0,
|
|
126
|
+
// Intrathecal methothrexate_grp: 0,
|
|
127
|
+
ced: 0,
|
|
128
|
+
//1.6, // Cyclophosphamide, 0.7692 mean 7692.
|
|
129
|
+
cisp: 0,
|
|
130
|
+
//300, // Cisplatin
|
|
131
|
+
dox: 0,
|
|
132
|
+
// Anthracycline, 3 mean 300 ml/m2
|
|
133
|
+
carbo: 0,
|
|
134
|
+
// Carboplatin
|
|
135
|
+
hdmtx: 0,
|
|
136
|
+
// High-Dose Methotrexate
|
|
137
|
+
// radiation
|
|
138
|
+
brain: 0,
|
|
139
|
+
//5.4,
|
|
140
|
+
chest: 0,
|
|
141
|
+
//2.4,
|
|
142
|
+
heart: 0,
|
|
143
|
+
pelvis: 0,
|
|
144
|
+
abd: 0
|
|
145
|
+
//2.4
|
|
146
|
+
});
|
|
147
|
+
export {
|
|
148
|
+
api
|
|
149
|
+
};
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import * as mds2_init from "#src/mds2.init.js";
|
|
2
|
+
import * as mds3_init from "#src/mds3.init.js";
|
|
3
|
+
import * as common from "#shared/common.js";
|
|
4
|
+
const api = {
|
|
5
|
+
endpoint: "getDataset",
|
|
6
|
+
// should rename to simply 'dataset', method is based on HTTP method
|
|
7
|
+
methods: {
|
|
8
|
+
get: {
|
|
9
|
+
init,
|
|
10
|
+
request: {
|
|
11
|
+
typeId: "any"
|
|
12
|
+
},
|
|
13
|
+
response: {
|
|
14
|
+
typeId: "any"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
post: {
|
|
18
|
+
alternativeFor: "get",
|
|
19
|
+
init
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function init({ genomes }) {
|
|
24
|
+
return function(req, res) {
|
|
25
|
+
try {
|
|
26
|
+
const genome = genomes[req.query.genome];
|
|
27
|
+
if (!genome)
|
|
28
|
+
throw "unknown genome";
|
|
29
|
+
if (!genome.datasets)
|
|
30
|
+
throw "genomeobj.datasets{} missing";
|
|
31
|
+
let ds;
|
|
32
|
+
for (const k in genome.datasets) {
|
|
33
|
+
if (k.toLowerCase() == req.query.dsname.toLowerCase()) {
|
|
34
|
+
ds = genome.datasets[k];
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!ds)
|
|
39
|
+
throw "invalid dsname";
|
|
40
|
+
if (ds.isMds3) {
|
|
41
|
+
return res.send({ ds: mds3_init.client_copy(ds) });
|
|
42
|
+
}
|
|
43
|
+
if (ds.isMds) {
|
|
44
|
+
return res.send({ ds: mds_clientcopy(ds) });
|
|
45
|
+
}
|
|
46
|
+
return res.send({ ds: copy_legacyDataset(ds) });
|
|
47
|
+
} catch (e) {
|
|
48
|
+
res.send({ error: e.message || e });
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function mds_clientcopy(ds) {
|
|
53
|
+
const ds2 = {
|
|
54
|
+
isMds: true,
|
|
55
|
+
noHandleOnClient: ds.noHandleOnClient,
|
|
56
|
+
label: ds.label,
|
|
57
|
+
version: ds.version,
|
|
58
|
+
annotationsampleset2matrix: ds.annotationsampleset2matrix,
|
|
59
|
+
mutationAttribute: ds.mutationAttribute,
|
|
60
|
+
locusAttribute: ds.locusAttribute,
|
|
61
|
+
alleleAttribute: ds.alleleAttribute,
|
|
62
|
+
// these are quick fixes and should be deleted later
|
|
63
|
+
hide_genotypedownload: ds.hide_genotypedownload,
|
|
64
|
+
hide_phewas: ds.hide_phewas,
|
|
65
|
+
sample2bam: ds.sample2bam
|
|
66
|
+
};
|
|
67
|
+
if (ds.queries) {
|
|
68
|
+
ds2.queries = {};
|
|
69
|
+
}
|
|
70
|
+
if (ds.track) {
|
|
71
|
+
ds2.track = mds2_init.client_copy(ds);
|
|
72
|
+
}
|
|
73
|
+
if (ds.singlesamplemutationjson) {
|
|
74
|
+
ds2.singlesamplemutationjson = 1;
|
|
75
|
+
}
|
|
76
|
+
if (ds.gene2mutcount) {
|
|
77
|
+
ds2.gene2mutcount = true;
|
|
78
|
+
ds2.mutCountType = ds.gene2mutcount.mutationTypes;
|
|
79
|
+
}
|
|
80
|
+
if (ds.assayAvailability) {
|
|
81
|
+
ds2.assayAvailability = 1;
|
|
82
|
+
}
|
|
83
|
+
if (ds.cohort && ds.cohort.sampleAttribute) {
|
|
84
|
+
const toclient = {};
|
|
85
|
+
for (const k in ds.cohort.sampleAttribute.attributes) {
|
|
86
|
+
const a = ds.cohort.sampleAttribute.attributes[k];
|
|
87
|
+
if (!a.clientnoshow)
|
|
88
|
+
toclient[k] = a;
|
|
89
|
+
}
|
|
90
|
+
ds2.sampleAttribute = { attributes: toclient };
|
|
91
|
+
}
|
|
92
|
+
if (ds.cohort) {
|
|
93
|
+
if (ds.cohort.termdb) {
|
|
94
|
+
ds2.termdb = {
|
|
95
|
+
selectCohort: ds.cohort.termdb.selectCohort
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (ds.cohort.attributes && ds.cohort.attributes.defaulthidden) {
|
|
99
|
+
ds2.cohortHiddenAttr = ds.cohort.attributes.defaulthidden;
|
|
100
|
+
}
|
|
101
|
+
if (ds.cohort.survivalplot) {
|
|
102
|
+
ds2.survivalplot = {
|
|
103
|
+
samplegroupattrlst: ds.cohort.survivalplot.samplegroupattrlst,
|
|
104
|
+
plots: []
|
|
105
|
+
};
|
|
106
|
+
for (const k in ds.cohort.survivalplot.plots) {
|
|
107
|
+
const p = ds.cohort.survivalplot.plots[k];
|
|
108
|
+
ds2.survivalplot.plots.push({
|
|
109
|
+
key: k,
|
|
110
|
+
name: p.name,
|
|
111
|
+
timelabel: p.timelabel
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (ds.cohort.mutation_signature) {
|
|
116
|
+
const sets = {};
|
|
117
|
+
for (const k in ds.cohort.mutation_signature.sets) {
|
|
118
|
+
const s = ds.cohort.mutation_signature.sets[k];
|
|
119
|
+
sets[k] = {
|
|
120
|
+
name: s.name,
|
|
121
|
+
signatures: s.signatures
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
ds2.mutation_signature = { sets };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const k in ds.queries) {
|
|
128
|
+
const q = ds.queries[k];
|
|
129
|
+
const clientquery = {
|
|
130
|
+
// revealed to client
|
|
131
|
+
name: q.name,
|
|
132
|
+
hideforthemoment: q.hideforthemoment
|
|
133
|
+
// hide track not ready to show on client
|
|
134
|
+
};
|
|
135
|
+
if (q.istrack) {
|
|
136
|
+
clientquery.istrack = true;
|
|
137
|
+
clientquery.type = q.type;
|
|
138
|
+
clientquery.isfull = q.isfull;
|
|
139
|
+
if (q.nochr != void 0) {
|
|
140
|
+
clientquery.nochr = q.nochr;
|
|
141
|
+
}
|
|
142
|
+
if (q.infoFilter) {
|
|
143
|
+
clientquery.infoFilter = q.infoFilter;
|
|
144
|
+
}
|
|
145
|
+
if (q.readcountCutoff) {
|
|
146
|
+
clientquery.readcountCutoff = q.readcountCutoff;
|
|
147
|
+
}
|
|
148
|
+
if (q.valueLabel) {
|
|
149
|
+
clientquery.valueLabel = q.valueLabel;
|
|
150
|
+
}
|
|
151
|
+
if (q.valueCutoff) {
|
|
152
|
+
clientquery.valueCutoff = q.valueCutoff;
|
|
153
|
+
}
|
|
154
|
+
if (q.bplengthUpperLimit) {
|
|
155
|
+
clientquery.bplengthUpperLimit = q.bplengthUpperLimit;
|
|
156
|
+
}
|
|
157
|
+
if (q.segmeanValueCutoff) {
|
|
158
|
+
clientquery.segmeanValueCutoff = q.segmeanValueCutoff;
|
|
159
|
+
}
|
|
160
|
+
if (q.lohLengthUpperLimit) {
|
|
161
|
+
clientquery.lohLengthUpperLimit = q.lohLengthUpperLimit;
|
|
162
|
+
}
|
|
163
|
+
if (q.type == common.tkt.mdssvcnv) {
|
|
164
|
+
if (q.groupsamplebyattr) {
|
|
165
|
+
clientquery.groupsamplebyattr = q.groupsamplebyattr;
|
|
166
|
+
}
|
|
167
|
+
clientquery.multihidelabel_fusion = q.multihidelabel_fusion;
|
|
168
|
+
clientquery.multihidelabel_sv = q.multihidelabel_sv;
|
|
169
|
+
clientquery.multihidelabel_vcf = q.multihidelabel_vcf;
|
|
170
|
+
clientquery.showfullmode = q.showfullmode;
|
|
171
|
+
clientquery.legend_vorigin = q.legend_vorigin;
|
|
172
|
+
clientquery.no_loh = q.no_loh;
|
|
173
|
+
if (q.expressionrank_querykey) {
|
|
174
|
+
const e = ds.queries[q.expressionrank_querykey];
|
|
175
|
+
clientquery.checkexpressionrank = {
|
|
176
|
+
querykey: q.expressionrank_querykey,
|
|
177
|
+
datatype: e.datatype
|
|
178
|
+
};
|
|
179
|
+
if (e.boxplotbysamplegroup && e.boxplotbysamplegroup.additionals) {
|
|
180
|
+
const lst = [];
|
|
181
|
+
if (e.boxplotbysamplegroup.attributes)
|
|
182
|
+
lst.push(e.boxplotbysamplegroup.attributes.map((i) => i.label).join(", "));
|
|
183
|
+
for (const i of e.boxplotbysamplegroup.additionals)
|
|
184
|
+
lst.push(i.label);
|
|
185
|
+
clientquery.checkexpressionrank.boxplotgroupers = lst;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (q.vcf_querykey) {
|
|
189
|
+
clientquery.checkvcf = {
|
|
190
|
+
querykey: q.vcf_querykey,
|
|
191
|
+
info: ds.queries[q.vcf_querykey].info,
|
|
192
|
+
format: {}
|
|
193
|
+
};
|
|
194
|
+
for (const tk of ds.queries[q.vcf_querykey].tracks) {
|
|
195
|
+
if (tk.format) {
|
|
196
|
+
for (const k2 in tk.format) {
|
|
197
|
+
clientquery.checkvcf.format[k2] = tk.format[k2];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} else if (q.isgenenumeric) {
|
|
204
|
+
clientquery.isgenenumeric = true;
|
|
205
|
+
clientquery.datatype = q.datatype;
|
|
206
|
+
clientquery.no_ase = q.no_ase;
|
|
207
|
+
} else {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
ds2.queries[k] = clientquery;
|
|
211
|
+
}
|
|
212
|
+
return ds2;
|
|
213
|
+
}
|
|
214
|
+
function copy_legacyDataset(ds) {
|
|
215
|
+
const ds2 = {
|
|
216
|
+
noHandleOnClient: ds.noHandleOnClient,
|
|
217
|
+
sampleselectable: ds.sampleselectable,
|
|
218
|
+
label: ds.label,
|
|
219
|
+
dsinfo: ds.dsinfo,
|
|
220
|
+
stratify: ds.stratify,
|
|
221
|
+
cohort: ds.cohort,
|
|
222
|
+
vcfinfofilter: ds.vcfinfofilter,
|
|
223
|
+
info2table: ds.info2table,
|
|
224
|
+
info2singletable: ds.info2singletable,
|
|
225
|
+
url4variant: ds.url4variant,
|
|
226
|
+
itemlabelname: ds.itemlabelname
|
|
227
|
+
};
|
|
228
|
+
if (ds.snvindel_attributes) {
|
|
229
|
+
ds2.snvindel_attributes = [];
|
|
230
|
+
for (const at of ds.snvindel_attributes) {
|
|
231
|
+
const rep = {};
|
|
232
|
+
for (const k in at) {
|
|
233
|
+
if (k == "lst") {
|
|
234
|
+
rep.lst = [];
|
|
235
|
+
for (const e of at.lst) {
|
|
236
|
+
const rep2 = {};
|
|
237
|
+
for (const k2 in e)
|
|
238
|
+
rep2[k2] = e[k2];
|
|
239
|
+
rep.lst.push(rep2);
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
rep[k] = at[k];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
ds2.snvindel_attributes.push(rep);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (ds.snvindel_legend) {
|
|
249
|
+
ds2.snvindel_legend = ds.snvindel_legend;
|
|
250
|
+
}
|
|
251
|
+
const vcfinfo = {};
|
|
252
|
+
let hasvcf = false;
|
|
253
|
+
for (const q of ds.queries) {
|
|
254
|
+
if (q.vcf) {
|
|
255
|
+
hasvcf = true;
|
|
256
|
+
vcfinfo[q.vcf.vcfid] = q.vcf;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (hasvcf) {
|
|
260
|
+
ds2.id2vcf = vcfinfo;
|
|
261
|
+
}
|
|
262
|
+
return ds2;
|
|
263
|
+
}
|
|
264
|
+
export {
|
|
265
|
+
api
|
|
266
|
+
};
|
package/routes/dsdata.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import serverconfig from "#src/serverconfig.js";
|
|
4
|
+
import * as common from "#shared/common.js";
|
|
5
|
+
const api = {
|
|
6
|
+
// route endpoint
|
|
7
|
+
// - no need for trailing slash
|
|
8
|
+
// - should be a noun (method is based on HTTP GET, POST, etc)
|
|
9
|
+
// - don't add 'Data' as response is assumed to be data
|
|
10
|
+
endpoint: "dsdata",
|
|
11
|
+
methods: {
|
|
12
|
+
get: {
|
|
13
|
+
init,
|
|
14
|
+
request: {
|
|
15
|
+
typeId: "any"
|
|
16
|
+
},
|
|
17
|
+
response: {
|
|
18
|
+
typeId: "any"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
post: {
|
|
22
|
+
alternativeFor: "get",
|
|
23
|
+
init
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
function init({ genomes }) {
|
|
28
|
+
return async function handle_dsdata(req, res) {
|
|
29
|
+
try {
|
|
30
|
+
if (!genomes[req.query.genome])
|
|
31
|
+
throw "invalid genome";
|
|
32
|
+
if (!req.query.dsname)
|
|
33
|
+
throw ".dsname missing";
|
|
34
|
+
const ds = genomes[req.query.genome].datasets[req.query.dsname];
|
|
35
|
+
if (!ds)
|
|
36
|
+
throw "invalid dsname";
|
|
37
|
+
const data = [];
|
|
38
|
+
for (const query of ds.queries) {
|
|
39
|
+
if (req.query.expressiononly && !query.isgeneexpression) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (req.query.noexpression && query.isgeneexpression) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (query.dsblocktracklst) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (query.vcffile) {
|
|
49
|
+
const d = await handle_dsdata_vcf(query, req);
|
|
50
|
+
data.push(d);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (query.makequery) {
|
|
54
|
+
const d = handle_dsdata_makequery(ds, query, req, genomes);
|
|
55
|
+
data.push(d);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
throw "unknow type from one of ds.queries[]";
|
|
59
|
+
}
|
|
60
|
+
res.send({ data });
|
|
61
|
+
} catch (e) {
|
|
62
|
+
if (e.stack)
|
|
63
|
+
console.log(e.stack);
|
|
64
|
+
res.send({ error: e.message || e });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function handle_dsdata_makequery(ds, query, req, genomes) {
|
|
69
|
+
if (req.query.isoform) {
|
|
70
|
+
if (genomes[req.query.genome].genomicNameRegexp.test(req.query.isoform))
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const [sqlstr, values] = query.makequery(req.query);
|
|
74
|
+
if (!sqlstr) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const rows = ds.newconn.prepare(sqlstr).all(values);
|
|
78
|
+
let lst;
|
|
79
|
+
if (query.tidy) {
|
|
80
|
+
lst = rows.map((i) => query.tidy(i));
|
|
81
|
+
} else {
|
|
82
|
+
lst = rows;
|
|
83
|
+
}
|
|
84
|
+
const result = {};
|
|
85
|
+
if (query.isgeneexpression) {
|
|
86
|
+
result.lst = lst;
|
|
87
|
+
result.isgeneexpression = true;
|
|
88
|
+
result.config = query.config;
|
|
89
|
+
for (const q2 of ds.queries) {
|
|
90
|
+
if (!q2.dsblocktracklst)
|
|
91
|
+
continue;
|
|
92
|
+
for (const tk of q2.dsblocktracklst) {
|
|
93
|
+
if (tk.type == common.tkt.junction) {
|
|
94
|
+
result.config.dsjunctiontk = tk;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
result.lst = lst;
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
function handle_dsdata_vcf(query, req) {
|
|
104
|
+
const par = [
|
|
105
|
+
path.join(serverconfig.tpmasterdir, query.vcffile),
|
|
106
|
+
(query.vcf.nochr ? req.query.range.chr.replace("chr", "") : req.query.range.chr) + ":" + req.query.range.start + "-" + req.query.range.stop
|
|
107
|
+
];
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
const ps = spawn(serverconfig.tabix, par);
|
|
110
|
+
const out = [], out2 = [];
|
|
111
|
+
ps.stdout.on("data", (i) => out.push(i));
|
|
112
|
+
ps.stderr.on("data", (i) => out2.push(i));
|
|
113
|
+
ps.on("close", (code) => {
|
|
114
|
+
const e = out2.join("").trim();
|
|
115
|
+
if (e != "")
|
|
116
|
+
reject("error querying vcf file");
|
|
117
|
+
const tmp = out.join("").trim();
|
|
118
|
+
resolve({
|
|
119
|
+
lines: tmp == "" ? [] : tmp.split("\n"),
|
|
120
|
+
vcfid: query.vcf.vcfid
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
api
|
|
127
|
+
};
|