@sjcrh/proteinpaint-server 2.26.1 → 2.27.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.
@@ -0,0 +1,97 @@
1
+ import { GdcTopVariablyExpressedGenesResponse } from '#shared/types/routes/gdc.topVariablyExpressedGenes.ts'
2
+ import { getCasesWithExressionDataFromCohort } from '../src/mds3.gdc.js'
3
+ //import path from 'path'
4
+ import got from 'got'
5
+ import serverconfig from '../src/serverconfig.js'
6
+
7
+ // TODO change when api is released to prod
8
+ //const apihost = process.env.PP_GDC_HOST || 'https://api.gdc.cancer.gov'
9
+ const apihost = 'https://uat-portal.gdc.cancer.gov/auth/api/v0/gene_expression/gene_selection'
10
+
11
+ const gdcGenome = 'hg38'
12
+ const gdcDslabel = 'GDC'
13
+
14
+ export const api = {
15
+ endpoint: 'gdc/topVariablyExpressedGenes',
16
+ methods: {
17
+ get: {
18
+ init({ genomes }) {
19
+ return async (req: any, res: any): Promise<void> => {
20
+ try {
21
+ // following logic requires hg38 gdc dataset
22
+ const genome = genomes[gdcGenome]
23
+ if (!genome) throw 'hg38 genome missing'
24
+ const ds = genome.datasets?.[gdcDslabel]
25
+ if (!ds) throw 'gdc dataset missing'
26
+ const genes = await getGenes(req.query, ds)
27
+ const payload = { genes } as GdcTopVariablyExpressedGenesResponse
28
+ res.send(payload)
29
+ } catch (e: any) {
30
+ res.send({ status: 'error', error: e.message || e })
31
+ }
32
+ }
33
+ },
34
+ request: {
35
+ typeId: null
36
+ //valid: default to type checker
37
+ },
38
+ response: {
39
+ typeId: 'GdcTopVariablyExpressedGenesResponse'
40
+ // will combine this with type checker
41
+ //valid: (t) => {}
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ /*
48
+ req.query {
49
+ filter0 // optional gdc GFF cohort filter, invisible and read only
50
+ FIXME should there be pp filter too?
51
+ maxGenes: int
52
+ }
53
+
54
+ ds { } // server-side ds object
55
+
56
+ */
57
+ async function getGenes(q: any, ds: any) {
58
+ if (serverconfig.features.gdcGenes) {
59
+ // for testing only; delete when api issue is resolved
60
+ return serverconfig.features.gdcGenes as string[]
61
+ }
62
+
63
+ // based on current cohort, get list of cases with exp data, as input of next api query
64
+ const caseLst = await getCasesWithExressionDataFromCohort(q, ds)
65
+ if (caseLst.length == 0) {
66
+ // there are no cases with gene exp data
67
+ return [] as string[]
68
+ }
69
+
70
+ // change to this when api is available on prod
71
+ // const url = path.join(apihost, '/gene_expression/gene_selection')
72
+
73
+ const response = await got.post(apihost, {
74
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
75
+ body: JSON.stringify({
76
+ case_ids: caseLst,
77
+ //gene_ids: [] // this should not be a required parameter
78
+ size: q.maxGenes || 100
79
+ })
80
+ })
81
+
82
+ const re = JSON.parse(response.body)
83
+ // {"gene_selection":[{"gene_id":"ENSG00000141510","log2_uqfpkm_median":3.103430497010492,"log2_uqfpkm_stddev":0.8692021350485105,"symbol":"TP53"}, ... ]}
84
+
85
+ const genes = [] as string[]
86
+ if (!Array.isArray(re.gene_selection)) throw 're.gene_selection[] is not array'
87
+ for (const i of re.gene_selection) {
88
+ if (i.gene_id && typeof i.gene_id == 'string') {
89
+ genes.push(i.gene_id) // ensg
90
+ } else if (i.symbol && typeof i.symbol == 'string') {
91
+ genes.push(i.symbol)
92
+ } else {
93
+ throw 'one of re.gene_selection[] is missing both gene_id and symbol'
94
+ }
95
+ }
96
+ return genes
97
+ }
@@ -1,11 +1,14 @@
1
1
  import { getResult } from '#src/gene.js'
2
+ import { GeneLookupRequest, GeneLookupResponse } from '#shared/types/routes/genelookup.ts'
2
3
 
3
4
  function init({ genomes }) {
4
5
  return (req: any, res: any): void => {
5
6
  try {
7
+ const q = req.query as GeneLookupRequest
6
8
  const g = genomes[req.query.genome]
7
9
  if (!g) throw 'invalid genome name'
8
- res.send(getResult(g, req.query))
10
+ const result = getResult(g, req.query) as GeneLookupResponse
11
+ res.send(result)
9
12
  } catch (e: any) {
10
13
  res.send({ error: e.message || e })
11
14
  if (e.stack) console.log(e.stack)
@@ -45,14 +48,3 @@ export const api: any = {
45
48
  }
46
49
  }
47
50
  }
48
-
49
- export type GeneLookupRequest = {
50
- input: string
51
- genome: string
52
- deep: boolean
53
- }
54
-
55
- export type GeneLookupResponse = {
56
- error?: string
57
- hits: string[]
58
- }
@@ -1,13 +1,14 @@
1
1
  import { getStat } from '#src/health.ts'
2
+ import { HealthCheckResponse } from '#shared/types/routes/healthcheck.ts'
2
3
 
3
4
  export const api = {
4
5
  endpoint: 'healthcheck',
5
6
  methods: {
6
7
  get: {
7
8
  init({ genomes }) {
8
- return async (req: any, res: any): Promise<void> => {
9
+ return async (req: undefined, res: any): Promise<void> => {
9
10
  try {
10
- const health = await getStat(genomes)
11
+ const health = (await getStat(genomes)) as HealthCheckResponse
11
12
  res.send(health)
12
13
  } catch (e: any) {
13
14
  res.send({ status: 'error', error: e.message || e })
@@ -26,47 +27,3 @@ export const api = {
26
27
  }
27
28
  }
28
29
  }
29
-
30
- /**
31
- * for documentation only, to signify integer: not type-checked statically
32
- */
33
- type int = number
34
-
35
- /**
36
- * Information aboute the server build version and dates,
37
- * including the date when the server was last launched
38
- */
39
- export type VersionInfo = {
40
- pkgver: string
41
- codedate: string
42
- launchdate: string
43
- }
44
-
45
- type BuildByGenome = {
46
- [index: string]: GenomeBuildInfo
47
- }
48
-
49
- export type GenomeBuildInfo = {
50
- genedb: DbInfo
51
- termdbs?: {
52
- [index: string]: DbInfo
53
- }
54
- }
55
-
56
- type DbInfo = {
57
- buildDate: string // "unknown" or a Date-convertible string
58
- tables?: {
59
- [index: string]: int
60
- }
61
- }
62
-
63
- /**
64
- * Server sttus and data related to it's health
65
- */
66
- export type HealthCheckResponse = {
67
- status: 'ok' | 'error'
68
- genomes: BuildByGenome
69
- versionInfo: VersionInfo
70
- w?: number[]
71
- rs?: number
72
- }
@@ -0,0 +1,78 @@
1
+ import { trigger_getViolinPlotData } from '#src/termdb.violin.js'
2
+ // import { getViolinRequest, getViolinResponse } from '#shared/types/routes/termdb.violin'
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
+ plotThickness: 150,
46
+ termid: 'agedx'
47
+ }
48
+ },
49
+ response: {
50
+ header: { status: 200 }
51
+ }
52
+ }
53
+ ]
54
+ },
55
+ post: {
56
+ alternativeFor: 'get',
57
+ init
58
+ }
59
+ }
60
+ }
61
+
62
+ function init({ genomes }) {
63
+ return async (req: any, res: any): Promise<void> => {
64
+ const q = req.query // as getViolinRequest
65
+ try {
66
+ const g = genomes[req.query.genome]
67
+ const ds = g.datasets[req.query.dslabel]
68
+ if (!g) throw 'invalid genome name'
69
+ const data = await trigger_getViolinPlotData(req.query, null, ds, g) // as getViolinResponse
70
+ res.send(data)
71
+ } catch (e) {
72
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
73
+ // @ts-ignore
74
+ res.send({ error: e?.message || e })
75
+ if (e instanceof Error && e.stack) console.log(e)
76
+ }
77
+ }
78
+ }