@gmod/nclist
Version:
Read features from JBrowse 1 format nested containment list JSON
78 lines • 3.23 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
//@ts-nocheck
const quick_lru_1 = __importDefault(require("quick-lru"));
const abortable_promise_cache_1 = __importDefault(require("@gmod/abortable-promise-cache"));
const util_ts_1 = require("./util.js");
/**
* For a JSON array that gets too large to load in one go, this class
* helps break it up into chunks and provides an
* async API for using the information in the array.
*/
class LazyArray {
constructor({ urlTemplate, chunkSize, length, cacheSize = 100, readFile }, baseUrl) {
this.urlTemplate = urlTemplate;
this.chunkSize = chunkSize;
this.length = length;
this.baseUrl = baseUrl === undefined ? '' : baseUrl;
this.readFile = readFile;
if (!readFile) {
throw new Error('must provide readFile callback');
}
this.chunkCache = new abortable_promise_cache_1.default({
cache: new quick_lru_1.default({ maxSize: cacheSize }),
fill: this.getChunk.bind(this),
});
}
/**
* call the callback on one element of the array
* @param i index
* @param callback callback, gets called with (i, value, param)
* @param param (optional) callback will get this as its last parameter
*/
index(i, callback, param) {
this.range(i, i, callback, undefined, param);
}
/**
* async generator for the elements in the range [start,end]
*
* @param start index of first element to call the callback on
* @param end index of last element to call the callback on
*/
async *range(start, end) {
start = Math.max(0, start);
end = Math.min(end, this.length - 1);
const firstChunk = Math.floor(start / this.chunkSize);
const lastChunk = Math.floor(end / this.chunkSize);
const chunkreadFiles = [];
for (let chunk = firstChunk; chunk <= lastChunk; chunk += 1) {
chunkreadFiles.push(this.chunkCache.get(chunk, chunk));
}
for (const elt of chunkreadFiles) {
const [chunkNumber, chunkData] = await elt;
yield* this.filterChunkData(start, end, chunkNumber, chunkData);
}
}
async getChunk(chunkNumber) {
let url = this.urlTemplate.replaceAll(/\{Chunk\}/gi, chunkNumber);
if (this.baseUrl) {
url = (0, util_ts_1.newURL)(url, this.baseUrl);
}
const data = await (0, util_ts_1.readJSON)(url, this.readFile);
return [chunkNumber, data];
}
*filterChunkData(queryStart, queryEnd, chunkNumber, chunkData) {
// index (in the overall lazy array) of the first position in this chunk
const firstIndex = chunkNumber * this.chunkSize;
const chunkStart = Math.max(0, queryStart - firstIndex);
const chunkEnd = Math.min(queryEnd - firstIndex, this.chunkSize - 1);
for (let i = chunkStart; i <= chunkEnd; i += 1) {
yield [i + firstIndex, chunkData[i]];
}
}
}
exports.default = LazyArray;
//# sourceMappingURL=lazy_array.js.map