Skip to content

Commit 9dba329

Browse files
committed
CSI fallback
1 parent 518920b commit 9dba329

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

src/tabixIndexedFile.ts

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ interface ReadChunk {
2828
export default class TabixIndexedFile {
2929
private filehandle: GenericFilehandle
3030
private index: IndexFile
31+
private fallbackIndex?: IndexFile
32+
private indexResolved = false
33+
private indexResolvePromise?: Promise<void>
3134
private renameRefSeq: (n: string) => string
3235
private chunkCache: AbortablePromiseCache<Chunk, ReadChunk>
3336
public cache = new LRU<
@@ -98,7 +101,16 @@ export default class TabixIndexedFile {
98101
throw new TypeError('must provide either filehandle or path')
99102
}
100103

101-
if (tbiFilehandle) {
104+
if (tbiFilehandle && csiFilehandle) {
105+
this.index = new TBI({
106+
filehandle: tbiFilehandle,
107+
renameRefSeqs,
108+
})
109+
this.fallbackIndex = new CSI({
110+
filehandle: csiFilehandle,
111+
renameRefSeqs,
112+
})
113+
} else if (tbiFilehandle) {
102114
this.index = new TBI({
103115
filehandle: tbiFilehandle,
104116
renameRefSeqs,
@@ -108,6 +120,15 @@ export default class TabixIndexedFile {
108120
filehandle: csiFilehandle,
109121
renameRefSeqs,
110122
})
123+
} else if (tbiPath && csiPath) {
124+
this.index = new TBI({
125+
filehandle: new LocalFile(tbiPath),
126+
renameRefSeqs,
127+
})
128+
this.fallbackIndex = new CSI({
129+
filehandle: new LocalFile(csiPath),
130+
renameRefSeqs,
131+
})
111132
} else if (tbiPath) {
112133
this.index = new TBI({
113134
filehandle: new LocalFile(tbiPath),
@@ -123,17 +144,37 @@ export default class TabixIndexedFile {
123144
filehandle: new LocalFile(`${path}.tbi`),
124145
renameRefSeqs,
125146
})
147+
this.fallbackIndex = new CSI({
148+
filehandle: new LocalFile(`${path}.csi`),
149+
renameRefSeqs,
150+
})
151+
} else if (tbiUrl && csiUrl) {
152+
this.index = new TBI({
153+
filehandle: new RemoteFile(tbiUrl),
154+
renameRefSeqs,
155+
})
156+
this.fallbackIndex = new CSI({
157+
filehandle: new RemoteFile(csiUrl),
158+
renameRefSeqs,
159+
})
126160
} else if (csiUrl) {
127161
this.index = new CSI({
128162
filehandle: new RemoteFile(csiUrl),
163+
renameRefSeqs,
129164
})
130165
} else if (tbiUrl) {
131166
this.index = new TBI({
132167
filehandle: new RemoteFile(tbiUrl),
168+
renameRefSeqs,
133169
})
134170
} else if (url) {
135171
this.index = new TBI({
136172
filehandle: new RemoteFile(`${url}.tbi`),
173+
renameRefSeqs,
174+
})
175+
this.fallbackIndex = new CSI({
176+
filehandle: new RemoteFile(`${url}.csi`),
177+
renameRefSeqs,
137178
})
138179
} else {
139180
throw new TypeError(
@@ -149,6 +190,38 @@ export default class TabixIndexedFile {
149190
})
150191
}
151192

193+
private async ensureIndex(opts: Options = {}) {
194+
if (this.indexResolved) {
195+
return
196+
}
197+
if (!this.indexResolvePromise) {
198+
this.indexResolvePromise = this.resolveIndex(opts)
199+
}
200+
return this.indexResolvePromise
201+
}
202+
203+
private async resolveIndex(opts: Options = {}) {
204+
if (!this.fallbackIndex) {
205+
this.indexResolved = true
206+
return
207+
}
208+
try {
209+
await this.index.parse(opts)
210+
this.indexResolved = true
211+
} catch (e) {
212+
const isNotFound =
213+
e instanceof Error &&
214+
(/HTTP 404/.test(e.message) || /ENOENT/.test(e.message))
215+
if (isNotFound) {
216+
this.index = this.fallbackIndex
217+
this.fallbackIndex = undefined
218+
this.indexResolved = true
219+
} else {
220+
throw e
221+
}
222+
}
223+
}
224+
152225
/**
153226
* @param refName name of the reference sequence
154227
*
@@ -195,6 +268,7 @@ export default class TabixIndexedFile {
195268
signal = opts.signal
196269
}
197270

271+
await this.ensureIndex(options)
198272
const metadata = await this.index.getMetadata(options)
199273
checkAbortSignal(signal)
200274
const start = s ?? 0
@@ -328,6 +402,7 @@ export default class TabixIndexedFile {
328402
}
329403

330404
async getMetadata(opts: Options = {}) {
405+
await this.ensureIndex(opts)
331406
return this.index.getMetadata(opts)
332407
}
333408

@@ -538,6 +613,7 @@ export default class TabixIndexedFile {
538613
* @returns number of data lines present on that reference sequence
539614
*/
540615
async lineCount(refName: string, opts: Options = {}) {
616+
await this.ensureIndex(opts)
541617
return this.index.lineCount(refName, opts)
542618
}
543619

0 commit comments

Comments
 (0)