@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.
Files changed (82) hide show
  1. package/dataset/clinvar.hg19.js +53 -52
  2. package/dataset/clinvar.hg38.js +74 -73
  3. package/dataset/clinvar.js +164 -47
  4. package/dataset/termdb.test.js +257 -0
  5. package/genome/CriGri.js +1859 -27
  6. package/genome/cgc.js +743 -7
  7. package/genome/danRer10.js +1108 -46
  8. package/genome/dm3.js +71 -44
  9. package/genome/dm6.js +1926 -45
  10. package/genome/galGal5.js +23522 -46
  11. package/genome/galGal6.js +512 -46
  12. package/genome/hg19.js +293 -198
  13. package/genome/hg38.js +472 -105
  14. package/genome/hg38.test.js +406 -40
  15. package/genome/hgvirus.js +45 -20
  16. package/genome/mm10.js +135 -67
  17. package/genome/mm9.js +116 -79
  18. package/genome/rn6.js +1002 -47
  19. package/package.json +31 -35
  20. package/routes/_template_.js +30 -0
  21. package/routes/burden.js +149 -0
  22. package/routes/dataset.js +266 -0
  23. package/routes/dsdata.js +127 -0
  24. package/routes/gdc.maf.js +120 -0
  25. package/routes/gdc.mafBuild.js +106 -0
  26. package/routes/gdc.topMutatedGenes.js +465 -0
  27. package/routes/gene2canonicalisoform.js +41 -0
  28. package/routes/genelookup.js +52 -0
  29. package/routes/genomes.js +144 -0
  30. package/routes/healthcheck.js +30 -0
  31. package/routes/hicdata.js +98 -0
  32. package/routes/hicstat.js +55 -0
  33. package/routes/isoformlst.js +57 -0
  34. package/routes/ntseq.js +43 -0
  35. package/routes/pdomain.js +61 -0
  36. package/routes/snp.js +107 -0
  37. package/routes/termdb.categories.js +209 -0
  38. package/routes/termdb.cluster.js +228 -0
  39. package/routes/termdb.cohort.summary.js +38 -0
  40. package/routes/termdb.cohorts.js +49 -0
  41. package/routes/termdb.config.js +202 -0
  42. package/routes/termdb.getdescrstats.js +102 -0
  43. package/routes/termdb.getnumericcategories.js +92 -0
  44. package/routes/termdb.getpercentile.js +108 -0
  45. package/routes/termdb.getrootterm.js +65 -0
  46. package/routes/termdb.gettermchildren.js +67 -0
  47. package/routes/termdb.singleSampleMutation.js +80 -0
  48. package/routes/termdb.singlecellData.js +46 -0
  49. package/routes/termdb.singlecellSamples.js +160 -0
  50. package/routes/termdb.termsbyids.js +59 -0
  51. package/routes/termdb.topVariablyExpressedGenes.js +171 -0
  52. package/routes/termdb.violin.js +77 -0
  53. package/src/app.js +41500 -0
  54. package/src/serverconfig.js +14 -8
  55. package/start.js +3 -3
  56. package/routes/README.md +0 -84
  57. package/routes/burden.ts +0 -143
  58. package/routes/gdc.maf.ts +0 -195
  59. package/routes/gdc.mafBuild.ts +0 -114
  60. package/routes/gdc.topMutatedGenes.ts +0 -586
  61. package/routes/genelookup.ts +0 -50
  62. package/routes/healthcheck.ts +0 -29
  63. package/routes/hicdata.ts +0 -111
  64. package/routes/hicstat.ts +0 -55
  65. package/routes/termdb.categories.ts +0 -245
  66. package/routes/termdb.cluster.ts +0 -248
  67. package/routes/termdb.getdescrstats.ts +0 -102
  68. package/routes/termdb.getnumericcategories.ts +0 -99
  69. package/routes/termdb.getpercentile.ts +0 -118
  70. package/routes/termdb.getrootterm.ts +0 -73
  71. package/routes/termdb.gettermchildren.ts +0 -82
  72. package/routes/termdb.singleSampleMutation.ts +0 -87
  73. package/routes/termdb.singlecellData.ts +0 -49
  74. package/routes/termdb.singlecellSamples.ts +0 -175
  75. package/routes/termdb.termsbyids.ts +0 -63
  76. package/routes/termdb.topVariablyExpressedGenes.ts +0 -214
  77. package/routes/termdb.violin.ts +0 -77
  78. package/server.js +0 -2
  79. package/server.js.map +0 -1
  80. package/shared/common.js +0 -1080
  81. package/shared/termdb.initbinconfig.js +0 -96
  82. package/shared/vcf.js +0 -629
@@ -1,175 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import { read_file } from '#src/utils.js'
4
- import serverconfig from '#src/serverconfig.js'
5
- import { SingleCellQuery, SingleCellSamplesNative, SingleCellDataNative } from '#shared/types/dataset.ts'
6
- import {
7
- Sample,
8
- TermdbSinglecellsamplesRequest,
9
- TermdbSinglecellsamplesResponse
10
- } from '#shared/types/routes/termdb.singlecellSamples.ts'
11
- import { Cell, Plot } from '#shared/types/routes/termdb.singlecellData.ts'
12
- import { gdc_validate_query_singleCell_samples, gdc_validate_query_singleCell_data } from '#src/mds3.gdc.js'
13
-
14
- /* route returns list of samples with sc data
15
- this is due to the fact that sometimes not all samples in a dataset has sc data
16
- */
17
-
18
- export const api: any = {
19
- endpoint: 'termdb/singlecellSamples',
20
- methods: {
21
- get: {
22
- init,
23
- request: {
24
- typeId: 'TermdbSinglecellsamplesRequest'
25
- },
26
- response: {
27
- typeId: 'TermdbSinglecellsamplesResponse'
28
- }
29
- },
30
- post: {
31
- alternativeFor: 'get',
32
- init
33
- }
34
- }
35
- }
36
-
37
- function init({ genomes }) {
38
- return async (req: any, res: any): Promise<void> => {
39
- const q = req.query as TermdbSinglecellsamplesRequest
40
- let result
41
- try {
42
- const g = genomes[q.genome]
43
- if (!g) throw 'invalid genome name'
44
- const ds = g.datasets[q.dslabel]
45
- if (!ds) throw 'invalid dataset name'
46
- if (!ds.queries?.singleCell) throw 'no singlecell data on this dataset'
47
- result = (await ds.queries.singleCell.samples.get(q)) as TermdbSinglecellsamplesResponse
48
- } catch (e: any) {
49
- if (e.stack) console.log(e.stack)
50
- result = {
51
- status: e.status || 400,
52
- error: e.message || e
53
- } as TermdbSinglecellsamplesResponse
54
- }
55
- res.send(result)
56
- }
57
- }
58
-
59
- /////////////////// ds query validator
60
- export async function validate_query_singleCell(ds: any, genome: any) {
61
- const q = ds.queries.singleCell as SingleCellQuery
62
- if (!q) return
63
-
64
- if (q.samples.src == 'gdcapi') {
65
- gdc_validate_query_singleCell_samples(ds, genome)
66
- } else if (q.samples.src == 'native') {
67
- getSamplesNative(q.samples as SingleCellSamplesNative, ds)
68
- } else {
69
- throw 'unknown singleCell.samples.src'
70
- }
71
- // q.samples.get() added
72
-
73
- if (q.data.src == 'gdcapi') {
74
- gdc_validate_query_singleCell_data(ds, genome)
75
- } else if (q.data.src == 'native') {
76
- getDataNative(q.data as SingleCellDataNative, ds)
77
- } else {
78
- throw 'unknown singleCell.data.src'
79
- }
80
- // q.data.get() added
81
- }
82
-
83
- async function getSamplesNative(S: SingleCellSamplesNative, ds: any) {
84
- // for now use this quick fix method to pull sample ids annotated by this term
85
- // to support situation where not all samples from a dataset has sc data
86
- const isSamples = ds.cohort.termdb.q.getAllValues4term(S.isSampleTerm)
87
- if (isSamples.size == 0) throw 'no samples found that are identified by isSampleTerm'
88
- const samples = [] as any // array of samples with sc data to be sent to client and list in table; cannot use Sample type for the use of "sampleid" temp property
89
- for (const sampleid of isSamples.keys()) {
90
- if (isSamples.get(sampleid) == '1')
91
- samples.push({
92
- sample: ds.cohort.termdb.q.id2sampleName(sampleid), // string name for display
93
- sampleid // temporarily kept to assign term value to each sample
94
- })
95
- }
96
- if (S.sampleColumns) {
97
- // has optional terms to show as table columns and annotate samples
98
- for (const term of S.sampleColumns) {
99
- const s2v = ds.cohort.termdb.q.getAllValues4term(term.termid) // map. k: sampleid, v: term value
100
- for (const s of samples) {
101
- if (s2v.has(s.sampleid)) s[term.termid] = s2v.get(s.sampleid)
102
- }
103
- }
104
- }
105
- for (const s of samples) delete s.sampleid
106
-
107
- S.get = () => {
108
- return { samples: samples as Sample[] }
109
- }
110
- }
111
-
112
- function getDataNative(D: SingleCellDataNative, ds: any) {
113
- const nameSet = new Set() // guard against duplicating plot names
114
- for (const plot of D.plots) {
115
- if (nameSet.has(plot.name)) throw 'duplicate plot.name'
116
- nameSet.add(plot.name)
117
- }
118
-
119
- // scoped and cached for runtime
120
- const _terms = [] as any
121
-
122
- for (const tid of D.termIds) {
123
- const t = ds.cohort.termdb.q.termjsonByOneid(tid)
124
- if (!t) throw 'invalid term id from queries.singleCell.data.termIds[]'
125
- _terms.push(t)
126
- }
127
- D.get = async q => {
128
- // if sample is int, may convert to string
129
- try {
130
- const tid2cellvalue = {}
131
- for (const tid of D.termIds) tid2cellvalue[tid] = {} // k: cell id, v: cell value for this term
132
- const plots = [] as Plot[] // given a sample name, collect every plot data for this sample and return
133
- for (const plot of D.plots) {
134
- const tsvfile = path.join(serverconfig.tpmasterdir, plot.folder, q.sample + plot.fileSuffix)
135
- try {
136
- await fs.promises.stat(tsvfile)
137
- } catch (e: any) {
138
- if (e.code == 'ENOENT') {
139
- // no file found for this sample; allowed because sampleView tests if that sample has sc data or not
140
- continue
141
- }
142
- if (e.code == 'EACCES') throw 'cannot read file, permission denied'
143
- throw 'failed to load sc data file'
144
- }
145
- const lines = (await read_file(tsvfile)).trim().split('\n')
146
- // 1st line is header
147
- const cells = [] as Cell[]
148
- for (let i = 1; i < lines.length; i++) {
149
- // each line is a cell
150
- const l = lines[i].split('\t')
151
- const cellId = l[0],
152
- x = Number(l[plot.coordsColumns.x]), // FIXME standardize, or define idx in plot
153
- y = Number(l[plot.coordsColumns.y])
154
- const category = l[plot.colorColumn?.index] || ''
155
- if (!cellId) throw 'cell id missing'
156
- if (!Number.isFinite(x) || !Number.isFinite(y)) throw 'x/y not number'
157
- cells.push({ cellId, x, y, category })
158
-
159
- for (const tid of D.termIds) {
160
- tid2cellvalue[tid][cellId] = l[1]
161
- }
162
- }
163
- plots.push({ name: plot.name, cells, colorBy: plot.colorColumn?.name, colorMap: plot.colorMap })
164
- }
165
- if (plots.length == 0) {
166
- // no data available for this sample
167
- return { nodata: true }
168
- }
169
- return { plots, terms: _terms, tid2cellvalue }
170
- } catch (e: any) {
171
- if (e.stack) console.log(e.stack)
172
- return { error: e.message || e }
173
- }
174
- }
175
- }
@@ -1,63 +0,0 @@
1
- import { gettermsbyidsRequest, gettermsbyidsResponse } from '#shared/types/routes/termdb.termsbyids.js'
2
- import { copy_term } from '#src/termdb.js'
3
-
4
- export const api: any = {
5
- endpoint: 'termdb/termsbyids',
6
- methods: {
7
- get: {
8
- init,
9
- request: {
10
- typeId: 'gettermsbyidsRequest'
11
- },
12
- response: {
13
- typeId: 'gettermsbyidsResponse'
14
- }
15
- },
16
- post: {
17
- alternativeFor: 'get',
18
- init
19
- }
20
- }
21
- }
22
-
23
- function init({ genomes }) {
24
- return async (req: any, res: any): Promise<void> => {
25
- const q = req.query // as getcategoriesRequest
26
- try {
27
- const g = genomes[req.query.genome]
28
- if (!g) throw 'invalid genome name'
29
- const ds = g.datasets[req.query.dslabel]
30
- if (!ds) throw 'invalid dataset name'
31
- const tdb = ds.cohort.termdb
32
- if (!tdb) throw 'invalid termdb object'
33
-
34
- await trigger_gettermsbyid(q, res, tdb) // as getcategoriesResponse
35
- } catch (e) {
36
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
37
- // @ts-ignore
38
- res.send({ error: e?.message || e })
39
- if (e instanceof Error && e.stack) console.log(e)
40
- }
41
- }
42
- }
43
-
44
- async function trigger_gettermsbyid(
45
- q: { ids: any },
46
- res: { send: (arg0: { terms: any }) => void },
47
- tdb: { q: { termjsonByOneid: (arg0: any) => any } }
48
- ) {
49
- const terms = {}
50
- for (const id of q.ids) {
51
- const term = tdb.q.termjsonByOneid(id)
52
- if (term) {
53
- if (term.type == 'categorical' && !term.values && !term.groupsetting?.inuse) {
54
- term.values = {}
55
- term.samplecount = {}
56
- }
57
- }
58
- terms[id] = term ? copy_term(term) : undefined
59
- }
60
- res.send({
61
- terms
62
- })
63
- }
@@ -1,214 +0,0 @@
1
- import {
2
- TermdbTopVariablyExpressedGenesRequest,
3
- TermdbTopVariablyExpressedGenesResponse
4
- } from '#shared/types/routes/termdb.topVariablyExpressedGenes.ts'
5
- import { gdcGetCasesWithExressionDataFromCohort } from '../src/mds3.gdc.js'
6
- import path from 'path'
7
- import { run_rust } from '@sjcrh/proteinpaint-rust'
8
- import got from 'got'
9
- import serverconfig from '#src/serverconfig.js'
10
- import { get_samples } from '#src/termdb.sql.js'
11
-
12
- export const api = {
13
- endpoint: 'termdb/topVariablyExpressedGenes',
14
- methods: {
15
- all: {
16
- init,
17
- request: {
18
- typeId: 'TermdbTopVariablyExpressedGenesRequest'
19
- },
20
- response: {
21
- typeId: 'TermdbTopVariablyExpressedGenesResponse'
22
- }
23
- }
24
- }
25
- }
26
-
27
- function init({ genomes }) {
28
- return async (req: any, res: any): Promise<void> => {
29
- try {
30
- const q = req.query as TermdbTopVariablyExpressedGenesRequest
31
- const genome = genomes[q.genome]
32
- if (!genome) throw 'invalid genome'
33
- const ds = genome.datasets?.[q.dslabel]
34
- if (!ds) throw 'invalid dslabel'
35
- if (!ds.queries?.topVariablyExpressedGenes) throw 'not supported on dataset'
36
-
37
- const t = Date.now()
38
- const genes = await ds.queries.topVariablyExpressedGenes.getGenes(q)
39
- if (serverconfig.debugmode) console.log('topVariablyExpressedGenes', Date.now() - t, 'ms')
40
-
41
- res.send({ genes } as TermdbTopVariablyExpressedGenesResponse)
42
- } catch (e: any) {
43
- res.send({ status: 'error', error: e.message || e })
44
- }
45
- }
46
- }
47
-
48
- export function validate_query_TopVariablyExpressedGenes(ds: any, genome: any) {
49
- const q = ds.queries.topVariablyExpressedGenes
50
- if (!q) return
51
- if (q.src == 'gdcapi') {
52
- gdcValidateQuery(ds, genome)
53
- } else if (q.src == 'native') {
54
- nativeValidateQuery(ds, genome)
55
- } else {
56
- throw 'unknown topVariablyExpressedGenes.src'
57
- }
58
- // added getter: q.getGenes()
59
- }
60
-
61
- function nativeValidateQuery(ds: any, genome: any) {
62
- const gE = ds.queries.geneExpression // a separate query required to supply data for computing top genes
63
- if (!gE) throw 'topVariablyExpressedGenes query given but geneExpression missing'
64
- if (gE.src != 'native') throw 'topVariablyExpressedGenes is native but geneExpression.src is not native'
65
-
66
- ds.queries.topVariablyExpressedGenes.getGenes = async (q: TermdbTopVariablyExpressedGenesRequest) => {
67
- // get list of samples that are used in current analysis; gE.samples[] contains all sample integer ids with exp data
68
- const samples = [] as string[]
69
- if (q.filter) {
70
- // get all samples pasing pp filter, may contain those without exp data
71
- const sidlst = await get_samples(q.filter, ds)
72
- // [{id:int}]
73
- // filter for those with exp data from q.samples[]
74
- for (const i of sidlst) {
75
- if (gE.samples.includes(i.id)) {
76
- // this sample passing filter also has exp data; convert to string name
77
- const n: string = ds.cohort.termdb.q.id2sampleName(i.id)
78
- if (!n) throw 'sample id cannot convert to string name'
79
- samples.push(n)
80
- }
81
- }
82
- } else {
83
- // no filter, use all samples with exp data
84
- for (const i of gE.samples) {
85
- const n: string = ds.cohort.termdb.q.id2sampleName(i.id)
86
- if (!n) throw 'sample id cannot convert to string name'
87
- samples.push(n)
88
- }
89
- }
90
-
91
- // call rust to compute top genes on these samples
92
- const genes = await computeGenes4nativeDs(q, ds, gE.file, samples)
93
- return genes
94
- }
95
- }
96
-
97
- async function computeGenes4nativeDs(
98
- q: TermdbTopVariablyExpressedGenesRequest,
99
- ds: any,
100
- matrixFile: string,
101
- samples: string[]
102
- ) {
103
- // The param option in input JSON is very important. It instructs what method will be used to calculate variation in the counts for a particular gene. It supports variance as well as interquartile region. This is based on the recommendation of this article https://www.frontiersin.org/articles/10.3389/fgene.2021.632620/full . This article recommends using interquartile region over variance.
104
- const input_json = {
105
- input_file: matrixFile,
106
- samples: samples.join(','),
107
- filter_extreme_values: true,
108
- num_genes: Number(q.maxGenes),
109
- param: 'var'
110
- }
111
- const rust_output = await run_rust('topGeneByExpressionVariance', JSON.stringify(input_json))
112
- const rust_output_list = rust_output.split('\n')
113
-
114
- let output_json
115
- for (const item of rust_output_list) {
116
- if (item.includes('output_json:')) {
117
- output_json = JSON.parse(item.replace('output_json:', ''))
118
- } else {
119
- console.log(item)
120
- }
121
- }
122
- const varGenes = output_json.map(i => i.gene_symbol)
123
- return varGenes
124
- }
125
-
126
- function gdcValidateQuery(ds: any, genome: any) {
127
- ds.queries.topVariablyExpressedGenes.getGenes = async (q: TermdbTopVariablyExpressedGenesRequest) => {
128
- if (serverconfig.features.gdcGenes) {
129
- // for testing on dev, must not set on prod!! delete to trigger api query
130
- console.log('!!GDC!! using serverconfig.features.gdcGenes[]')
131
- return serverconfig.features.gdcGenes as string[]
132
- }
133
-
134
- // disable when caching is incomplete (particularly cases with gene exp data); to prevent showing wrong data on client
135
- if (!ds.__gdc.doneCaching) throw 'The server has not finished caching the case IDs: try again in ~2 minutes'
136
-
137
- // based on current cohort, get list of cases with exp data, as input of next api query
138
- const caseLst = await gdcGetCasesWithExressionDataFromCohort(q, ds)
139
- if (caseLst.length == 0) {
140
- // there are no cases with gene exp data
141
- return [] as string[]
142
- }
143
-
144
- // change to this when api is available on prod
145
- const { host, headers } = ds.getHostHeaders(q)
146
- const url = path.join(host.geneExp, '/gene_expression/gene_selection')
147
- try {
148
- const response = await got.post(url, {
149
- headers,
150
- body: JSON.stringify(getGeneSelectionArg(q, caseLst))
151
- })
152
-
153
- const re = JSON.parse(response.body)
154
- // {"gene_selection":[{"gene_id":"ENSG00000141510","log2_uqfpkm_median":3.103430497010492,"log2_uqfpkm_stddev":0.8692021350485105,"symbol":"TP53"}, ... ]}
155
-
156
- const genes = [] as string[]
157
- if (!Array.isArray(re.gene_selection)) throw 're.gene_selection[] is not array'
158
- for (const i of re.gene_selection) {
159
- if (i.gene_id && typeof i.gene_id == 'string') {
160
- // is ensg, convert to symbol
161
- const t = genome.genedb.getNameByAlias.get(i.gene_id)
162
- if (t) genes.push(t.name) // ensg
163
- } else if (i.symbol && typeof i.symbol == 'string') {
164
- genes.push(i.symbol)
165
- } else {
166
- throw 'one of re.gene_selection[] is missing both gene_id and symbol'
167
- }
168
- }
169
- return genes
170
- } catch (e: any) {
171
- console.log(e.stack || e)
172
- throw e
173
- }
174
- }
175
-
176
- function getGeneSelectionArg(q: any, caseLst: any) {
177
- //to hide messy logic during testing phase
178
-
179
- /* when api performance issue is resolved, return this
180
- return {
181
- case_ids: caseLst,
182
- gene_type:'protein_coding',
183
- selection_size: Number(q.maxGenes)
184
- }
185
- */
186
-
187
- //////////////////////////////////////////////////
188
- //
189
- // !!!!!!!!!!!!!!!! TEMPORARY !!!!!!!!!!!!!!!!!!!!
190
- //
191
- //////////////////////////////////////////////////
192
- // limit the case_ids length, and restrict pool to CGC genes, otherwise the request times out !!!
193
- // must revert asap
194
- return {
195
- case_ids: caseLst, //.slice(0, 20),
196
- gene_ids: tempGetCGCgenes(genome),
197
- selection_size: Number(q.maxGenes)
198
- }
199
- }
200
- }
201
-
202
- function tempGetCGCgenes(genome: any) {
203
- const lst = [] as string[] // list of ENSG ids from cgc genes
204
- // don't think there's need to preparse genome.geneset, as this function is only temporary
205
- for (const s of genome.geneset[0].lst) {
206
- const a = genome.genedb.getAliasByName.all(s)
207
- if (a) {
208
- for (const b of a) {
209
- if (b.alias.startsWith('ENSG')) lst.push(b.alias)
210
- }
211
- }
212
- }
213
- return lst
214
- }
@@ -1,77 +0,0 @@
1
- import { getViolinRequest, getViolinResponse } from '#shared/types/routes/termdb.violin.ts'
2
- import { trigger_getViolinPlotData } from '#src/termdb.violin.js'
3
-
4
- export const api: any = {
5
- endpoint: 'termdb/violin',
6
- methods: {
7
- get: {
8
- init,
9
- request: {
10
- typeId: 'getViolinRequest'
11
- },
12
- response: {
13
- typeId: 'getViolinResponse'
14
- },
15
- examples: [
16
- {
17
- request: {
18
- body: {
19
- genome: 'hg38-test',
20
- dslabel: 'TermdbTest',
21
- embedder: 'localhost',
22
- devicePixelRatio: 2.200000047683716,
23
- maxThickness: 150,
24
- screenThickness: 1218,
25
- filter: {
26
- type: 'tvslst',
27
- in: true,
28
- join: '',
29
- lst: [
30
- {
31
- tag: 'cohortFilter',
32
- type: 'tvs',
33
- tvs: { term: { id: 'subcohort', type: 'categorical' }, values: [{ key: 'ABC', label: 'ABC' }] }
34
- }
35
- ]
36
- },
37
- svgw: 227.27272234672367,
38
- orientation: 'horizontal',
39
- datasymbol: 'bean',
40
- radius: 5,
41
- strokeWidth: 0.2,
42
- axisHeight: 60,
43
- rightMargin: 50,
44
- unit: 'abs',
45
- termid: 'agedx'
46
- }
47
- },
48
- response: {
49
- header: { status: 200 }
50
- }
51
- }
52
- ]
53
- },
54
- post: {
55
- alternativeFor: 'get',
56
- init
57
- }
58
- }
59
- }
60
-
61
- function init({ genomes }) {
62
- return async (req: any, res: any): Promise<void> => {
63
- const q = req.query as getViolinRequest
64
- try {
65
- const g = genomes[req.query.genome]
66
- const ds = g.datasets[req.query.dslabel]
67
- if (!g) throw 'invalid genome name'
68
- const data = await trigger_getViolinPlotData(req.query, null, ds, g) // as getViolinResponse
69
- res.send(data as getViolinResponse)
70
- } catch (e) {
71
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
72
- // @ts-ignore
73
- res.send({ error: e?.message || e })
74
- if (e instanceof Error && e.stack) console.log(e)
75
- }
76
- }
77
- }