• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IGVF-DACC / igvf-catalog / f04c4eff-3c13-4478-a29c-13ca879b262f

13 Nov 2025 08:02PM UTC coverage: 86.995% (+0.08%) from 86.919%
f04c4eff-3c13-4478-a29c-13ca879b262f

push

circleci

web-flow
DSERV-1086-schema-yaml (#559)

290 of 361 branches covered (80.33%)

Branch coverage included in aggregate %.

75 of 77 new or added lines in 14 files covered. (97.4%)

20 existing lines in 2 files now uncovered.

7443 of 8528 relevant lines covered (87.28%)

1.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/src/routers/datatypeRouters/nodes/proteins.ts
1
import { z } from 'zod'
1✔
2
import { db } from '../../../database'
1✔
3
import { QUERY_LIMIT } from '../../../constants'
1✔
4
import { publicProcedure } from '../../../trpc'
1✔
5
import { getDBReturnStatements, getFilterStatements, paramsFormatType } from '../_helpers'
1✔
6
import { descriptions } from '../descriptions'
1✔
7
import { TRPCError } from '@trpc/server'
1✔
8
import { commonNodesParamsFormat } from '../params'
1✔
9
import { getSchema } from '../schema'
1✔
10

1✔
11
const MAX_PAGE_SIZE = 50
1✔
12

1✔
13
const SEARCH_ALIAS = 'proteins_text_en_no_stem_inverted_search_alias'
1✔
14

1✔
15
const proteinSchema = getSchema('data/schemas/nodes/proteins.GencodeProtein.json')
1✔
16
const proteinCollectionName = proteinSchema.db_collection_name as string
1✔
17

1✔
18
export const proteinsQueryFormat = z.object({
1✔
19
  protein_id: z.string().trim().optional(),
1✔
20
  name: z.string().trim().optional(),
1✔
21
  full_name: z.string().trim().optional(),
1✔
22
  dbxrefs: z.string().trim().optional()
1✔
23
}).merge(commonNodesParamsFormat)
1✔
24
const dbxrefFormat = z.object({ name: z.string(), id: z.string() })
1✔
25

1✔
26
export const proteinFormat = z.object({
1✔
27
  _id: z.string(),
1✔
28
  names: z.array(z.string()).nullish(),
1✔
29
  full_names: z.array(z.string()).nullish(),
1✔
30
  dbxrefs: z.array(dbxrefFormat).nullish(),
1✔
31
  organism: z.string(),
1✔
32
  source: z.string(),
1✔
33
  source_url: z.string()
1✔
34
})
1✔
35

1✔
UNCOV
36
export function proteinByIDQuery (proteinId: string): string {
×
UNCOV
37
  return `(
×
NEW
38
    FOR record IN ${proteinCollectionName}
×
39
    FILTER record._key == '${decodeURIComponent(proteinId)}' OR
×
40
            record.protein_id == '${decodeURIComponent(proteinId)}' OR
×
41
            '${decodeURIComponent(proteinId)}' IN record.uniprot_ids
×
42
    RETURN record._id
×
43
  )
×
44
  `
×
45
}
×
46

1✔
47
async function findProteinByID (proteinId: string): Promise<any[]> {
2✔
48
  const query = `
2✔
49
    FOR record IN ${proteinCollectionName}
2✔
50
    FILTER record._key == '${decodeURIComponent(proteinId)}' OR
2✔
51
            record.protein_id == '${decodeURIComponent(proteinId)}' OR
2✔
52
            '${decodeURIComponent(proteinId)}' IN record.uniprot_ids
2✔
53
    RETURN { ${getDBReturnStatements(proteinSchema)} }
2✔
54
  `
2✔
55

2✔
56
  const record = (await (await db.query(query)).all())[0]
2✔
57

2✔
58
  if (record === undefined) {
2✔
59
    throw new TRPCError({
1✔
60
      code: 'NOT_FOUND',
1✔
61
      message: `Record ${proteinId} not found.`
1✔
62
    })
1✔
63
  }
1✔
64

1✔
65
  return record
1✔
66
}
2✔
67

1✔
68
async function findProteins (input: paramsFormatType): Promise<any[]> {
6✔
69
  let limit = QUERY_LIMIT
6✔
70
  if (input.limit !== undefined) {
6!
71
    limit = (input.limit as number <= MAX_PAGE_SIZE) ? input.limit as number : MAX_PAGE_SIZE
×
72
    delete input.limit
×
73
  }
×
74

6✔
75
  const filters = []
6✔
76
  if (input.name !== undefined) {
6✔
77
    const name = input.name as string
4✔
78
    delete input.name
4✔
79
    filters.push(`"${decodeURIComponent(name.toUpperCase())}" in record.names`)
4✔
80
  }
4✔
81

6✔
82
  if (input.full_name !== undefined) {
6✔
83
    const fullName = input.full_name as string
1✔
84
    delete input.full_name
1✔
85
    filters.push(`"${decodeURIComponent(fullName)}" in record.full_names`)
1✔
86
  }
1✔
87

6✔
88
  filters.push(getFilterStatements(proteinSchema, input))
6✔
89

6✔
90
  const filterBy = filters.length > 0 ? `FILTER ${filters.join(' AND ')}` : ''
6!
91

6✔
92
  const query = `
6✔
93
    FOR record IN ${proteinCollectionName}
6✔
94
    ${filterBy}
6✔
95
    SORT record.chr
6✔
96
    LIMIT ${input.page as number * limit}, ${limit}
6✔
97
    RETURN { ${getDBReturnStatements(proteinSchema)} }
6✔
98
  `
6✔
99

6✔
100
  return await (await db.query(query)).all()
6✔
101
}
6✔
102

1✔
103
async function findProteinsByPrefixSearch (name: string, fullName: string, dbxrefs: string, filters: string, page: number, limit: number): Promise<any[]> {
2✔
104
  const fields: Record<string, string | undefined> = { names: name, full_names: fullName, 'dbxrefs.id': dbxrefs }
2✔
105
  const searchFilters = []
2✔
106
  for (const field in fields) {
2✔
107
    if (fields[field] !== undefined) {
6✔
108
      searchFilters.push(`STARTS_WITH(record.${field}, TOKENS("${decodeURIComponent(fields[field] as string)}", 'text_en_no_stem'))`)
2✔
109
    }
2✔
110
  }
6✔
111

2✔
112
  const query = `
2✔
113
    FOR record IN ${SEARCH_ALIAS}
2✔
114
    SEARCH ${searchFilters.join(' AND ')}
2✔
115
    ${filters}
2✔
116
    SORT BM25(record) DESC
2✔
117
    LIMIT ${page * limit}, ${limit}
2✔
118
    RETURN { ${getDBReturnStatements(proteinSchema)} }
2✔
119
  `
2✔
120

2✔
121
  return await (await db.query(query)).all()
2✔
122
}
2✔
123

1✔
124
async function findProteinsByFuzzySearch (name: string, fullName: string, dbxrefs: string, filters: string, page: number, limit: number): Promise<any[]> {
1✔
125
  const fields: Record<string, string | undefined> = { names: name, full_names: fullName, 'dbxrefs.id': dbxrefs }
1✔
126
  const searchFilters = []
1✔
127
  for (const field in fields) {
1✔
128
    if (fields[field] !== undefined) {
3✔
129
      searchFilters.push(`LEVENSHTEIN_MATCH(record.${field}, "${decodeURIComponent(fields[field] as string)}", 3, true)`)
1✔
130
    }
1✔
131
  }
3✔
132

1✔
133
  const query = `
1✔
134
    FOR record IN ${SEARCH_ALIAS}
1✔
135
    SEARCH ${searchFilters.join(' AND ')}
1✔
136
    ${filters}
1✔
137
    SORT BM25(record) DESC
1✔
138
    LIMIT ${page * limit}, ${limit}
1✔
139
    RETURN { ${getDBReturnStatements(proteinSchema)} }
1✔
140
  `
1✔
141

1✔
142
  return await (await db.query(query)).all()
1✔
143
}
1✔
144

1✔
145
async function findProteinsByTextSearch (input: paramsFormatType): Promise<any[]> {
6✔
146
  const name = input.name as string
6✔
147
  const fullName = input.full_name as string
6✔
148
  const dbxrefs = input.dbxrefs as string
6✔
149

6✔
150
  let limit = QUERY_LIMIT
6✔
151
  if (input.limit !== undefined) {
6✔
152
    limit = (input.limit as number <= MAX_PAGE_SIZE) ? input.limit as number : MAX_PAGE_SIZE
1!
153
    delete input.limit
1✔
154
  }
1✔
155

6✔
156
  // try exact match
6✔
157
  const exactObjects = await findProteins(input)
6✔
158
  if (exactObjects.length !== 0) {
6✔
159
    return exactObjects
4✔
160
  }
4✔
161

2✔
162
  delete input.name
2✔
163
  delete input.full_name
2✔
164
  delete input.dbxrefs
2✔
165

2✔
166
  let remainingFilters = getFilterStatements(proteinSchema, input)
2✔
167
  if (remainingFilters) {
6!
168
    remainingFilters = `FILTER ${remainingFilters}`
×
169
  }
×
170

2✔
171
  // try prefix match
2✔
172
  const prefixObjects = await findProteinsByPrefixSearch(name, fullName, dbxrefs, remainingFilters, input.page as number, limit)
2✔
173
  if (prefixObjects.length !== 0) {
6✔
174
    return prefixObjects
1✔
175
  }
1✔
176

1✔
177
  // try fuzzy match
1✔
178
  return await findProteinsByFuzzySearch(name, fullName, dbxrefs, remainingFilters, input.page as number, limit)
1✔
179
}
6✔
180

1✔
181
async function proteinSearch (input: paramsFormatType): Promise<any[]> {
8✔
182
  if ('protein_id' in input) {
8✔
183
    return await findProteinByID(input.protein_id as string)
2✔
184
  }
8✔
185

8✔
186
  if ('name' in input || 'full_name' in input || 'dbxrefs' in input) {
8!
187
    return await findProteinsByTextSearch(input)
8✔
188
  }
8✔
189

8✔
190
  return await findProteins(input)
8!
191
}
8✔
192

1✔
193
const proteins = publicProcedure
1✔
194
  .meta({ openapi: { method: 'GET', path: '/proteins', description: descriptions.proteins } })
1✔
195
  .input(proteinsQueryFormat)
1✔
196
  .output(z.array(proteinFormat).or(proteinFormat))
1✔
197
  .query(async ({ input }) => await proteinSearch(input))
1✔
198

1✔
199
export const proteinsRouters = {
1✔
200
  proteins
1✔
201
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc