UNPKG

azurite

Version:

An open source Azure Storage API compatible server

176 lines 5.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * This implements a page of blob results taking delimiters into account. * * When a delimiter is passed to list blobs, items must be squashed into BlobPrefix items. * When maxResults is smaller than the number of prefixed items in the metadata source, multiple reads from * the source may be necessary. * * @export * @class PageWithDelimiter */ class PageWithDelimiter { constructor(maxResults, delimiter, prefix) { this.prefixLength = 0; this.blobItems = []; this.blobPrefixes = new Set(); this.latestMarker = ""; // isFull indicates we could only (maybe) add a prefix this.isFull = false; // isExhausted indicates nothing more should be added this.isExhausted = false; this.maxResults = maxResults; if (delimiter !== undefined) { this.delimiter = delimiter; } if (prefix !== undefined) { this.prefix = prefix; this.prefixLength = prefix.length; } } /** * Empty the page (useful in unit tests) * */ reset() { this.blobItems.splice(0); this.blobPrefixes.clear(); this.isFull = false; this.isExhausted = false; this.latestMarker = ""; } updateFull() { this.isFull = (this.blobItems.length + this.blobPrefixes.size === this.maxResults); } /** * addItem will add to the blob list if possible and update the full/exhausted state of the page */ addItem(item) { if (this.isExhausted) { return false; } let added = false; if (!this.isFull) { this.blobItems.push(item); added = true; } this.updateFull(); // if a blob causes fullness the next item read cannot be squashed only duplicate prefixes can this.isExhausted = this.isFull; return added; } /** * addItem will add to the blob list if possible and update the full/exhausted state of the page */ addPrefix(prefix) { if (this.isExhausted) { return false; } let added = false; if (this.isFull) { // the page is exhausted if this prefix is new, only matching prefixes may be 'added' this.isExhausted = !this.blobPrefixes.has(prefix); added = !this.isExhausted; } else { this.blobPrefixes.add(prefix); added = true; } this.updateFull(); return added; } /** * Add a BlobType item to the appropriate collection, update the marker * * If no delimiter is used, items are all treated as blobs until maxResults is reached * * If a delimiter is used, the name will be checked for to see if the item should * be treated as a blob or a BlobPrefix. * * When the page becomes full, items may still be added iff the item is existing prefix * * Return the number of items added */ add(name, item) { if (this.isExhausted) { return false; } if (name < this.latestMarker) { throw new Error("add received unsorted item. add must be called on sorted data"); } const marker = (name > this.latestMarker) ? name : this.latestMarker; let added = false; if (this.delimiter !== undefined) { const delimiterPosAfterPrefix = name.indexOf(this.delimiter, this.prefixLength); if (delimiterPosAfterPrefix < 0) { added = this.addItem(item); } else { const prefix = name.substr(0, delimiterPosAfterPrefix + 1); added = this.addPrefix(prefix); } } else { added = this.addItem(item); } if (added) { this.latestMarker = marker; } return added; } /** * Iterate over an array blobs read from a source and add them until the page cannot accept new items */ processList(docs, nameFn) { let added = 0; for (const item of docs) { if (this.add(nameFn(item), item)) { added++; } if (this.isExhausted) break; } return added; } /** * Fill the page if possible by using the provided reader function. * * For any BlobType, the name is used with delimiter to treat the item as a blob or * a BlobPrefix for the list blobs result. * * This function will use the reader for BlobType to keep reading from a metadata * data source until the source has no more items or the page cannot add any more items. * * Return the contents of the page, blobs, prefixes, and a continuation token if applicable */ async fill(reader, namer) { let offset = 0; let docs = await reader(offset); let added = 0; while (docs.length) { added = this.processList(docs, namer); offset += added; if (added < this.maxResults) { break; } docs = await reader(offset); } return [ this.blobItems, this.prefixes(), added < docs.length ? this.latestMarker : "" ]; } prefixes() { const prefixes = []; const iter = this.blobPrefixes.values(); let val; while (!(val = iter.next()).done) { prefixes.push({ name: val.value }); } return prefixes; } } exports.default = PageWithDelimiter; //# sourceMappingURL=PageWithDelimiter.js.map