From fc9f9d9b87fc8ca81ede75606e0c78fe01d66150 Mon Sep 17 00:00:00 2001 From: Jeremy Scheff Date: Wed, 19 Apr 2017 09:50:51 -0400 Subject: [PATCH] Complete use of range in FDBCursor._iterate --- TODO | 8 ++--- src/FDBCursor.js | 73 ++++++++++++++++++++++++++---------------- src/lib/RecordStore.js | 16 +++++++-- 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/TODO b/TODO index b82b84bd..d5924c2d 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,9 @@ # v2 stuff: -abstract data functions -- FDBCursor._iterate - - don't start searching at record 0 if we know there is a lower bound. same with upper bound, can stop after passing it - - store lower bound to start iterator (don't worry about making it precise, including value and gt/gte), and upper bound to stop, based on various inputs - binary search tree TypeScript +- tslint Run on real W3C tests @@ -21,6 +17,8 @@ addDomStringListMethods - make it a class add lib.js for 1.x compatability, and test +make sure it works in node 4 + --- test that IDBObjectStore.index returns the same or different IDBIndex depending on situation http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-index-IDBIndex-DOMString-name diff --git a/src/FDBCursor.js b/src/FDBCursor.js index e3aa57a3..108cf003 100644 --- a/src/FDBCursor.js +++ b/src/FDBCursor.js @@ -12,7 +12,35 @@ const getEffectiveObjectStore = (cursor) => { return cursor.source; }; -const makeKeyRange = (lower, upper) => { +// This takes a key range, a list of lower bounds, and a list of upper bounds and combines them all into a single key +// range. It does not handle gt/gte distinctions, because it doesn't really matter much anyway, since for next/prev +// cursor iteration it'd also have to look at values to be precise, which would be complicated. This should get us 99% +// of the way there. +const makeKeyRange = (range, lowers, uppers) => { + // Start with bounds from range + let lower = range !== undefined ? range.lower : undefined; + let upper = range !== undefined ? range.upper : undefined; + + // Augment with values from lowers and uppers + for (const lowerTemp of lowers) { + if (lowerTemp === undefined) { + continue; + } + + if (lower === undefined || cmp(lower, lowerTemp) === 1) { + lower = lowerTemp; + } + } + for (const upperTemp of uppers) { + if (upperTemp === undefined) { + continue; + } + + if (upper === undefined || cmp(upper, upperTemp) === -1) { + upper = upperTemp; + } + } + if (lower !== undefined && upper !== undefined) { return FDBKeyRange.bound(lower, upper); } @@ -61,7 +89,8 @@ class FDBCursor { let foundRecord; if (this.direction === "next") { - for (const record of records.values()) { + const range = makeKeyRange(this._range, [key, this._position], []); + for (const record of records.values(range)) { if (key !== undefined) { if (cmp(record.key, key) === -1) { continue; @@ -90,29 +119,10 @@ class FDBCursor { break; } } else if (this.direction === "nextunique") { - let lower; - let upper; - if (key !== undefined) { - lower = key; - } - if (this._position !== undefined) { - if (lower === undefined || cmp(lower, this._position) === 1) { - lower = this._position; - } - } - if (this._range !== undefined) { - if (this._range.lower !== undefined && (lower === undefined || cmp(lower, this._range.lower) === 1)) { - lower = this._range.lower; - } - if (this._range.upper !== undefined) { - upper = this._range.upper; - } - } - const range = makeKeyRange(lower, upper); - // This could be done without iterating, if the range was defined slightly better (to handle gt/gte cases). // But the performance difference should be small, and that wouldn't work anyway for directions where the // value needs to be used (like next and prev). + const range = makeKeyRange(this._range, [key, this._position], []); for (const record of records.values(range)) { if (key !== undefined) { if (cmp(record.key, key) === -1) { @@ -133,7 +143,8 @@ class FDBCursor { break; } } else if (this.direction === "prev") { - for (const record of records.values(undefined, 'prev')) { + const range = makeKeyRange(this._range, [], [key, this._position]); + for (const record of records.values(range, 'prev')) { if (key !== undefined) { if (cmp(record.key, key) === 1) { continue; @@ -163,7 +174,8 @@ class FDBCursor { } } else if (this.direction === "prevunique") { let tempRecord; - for (const record of records.values(undefined, 'prev')) { + const range = makeKeyRange(this._range, [], [key, this._position]); + for (const record of records.values(range, 'prev')) { if (key !== undefined) { if (cmp(record.key, key) === 1) { continue; @@ -192,17 +204,24 @@ class FDBCursor { if (!foundRecord) { this._key = undefined; if (!sourceIsObjectStore) { this._objectStorePosition = undefined; } - this.value = undefined; + if (this.constructor.name === 'FDBCursorWithValue') { + this.value = undefined; + } result = null; } else { this._position = foundRecord.key; if (!sourceIsObjectStore) { this._objectStorePosition = foundRecord.value; } this._key = foundRecord.key; if (sourceIsObjectStore) { - this.value = structuredClone(foundRecord.value); + this._primaryKey = structuredClone(foundRecord.key); + if (this.constructor.name === 'FDBCursorWithValue') { + this.value = structuredClone(foundRecord.value); + } } else { - this.value = structuredClone(this.source.objectStore._rawObjectStore.getValue(foundRecord.value)); this._primaryKey = structuredClone(foundRecord.value); + if (this.constructor.name === 'FDBCursorWithValue') { + this.value = structuredClone(this.source.objectStore._rawObjectStore.getValue(foundRecord.value)); + } } this._gotValue = true; result = this; diff --git a/src/lib/RecordStore.js b/src/lib/RecordStore.js index 65ba74b3..5f8e1a3d 100644 --- a/src/lib/RecordStore.js +++ b/src/lib/RecordStore.js @@ -101,7 +101,12 @@ class RecordStore { } } } else { - i = this._records.length; + i = this._records.length - 1; + if (range !== undefined && range.upper !== undefined) { + while (this._records[i] !== undefined && cmp(this._records[i].key, range.upper) === 1) { + i -= 1; + } + } } return { @@ -120,9 +125,16 @@ class RecordStore { } } } else { - i -= 1; value = this._records[i]; done = i < 0; + i -= 1; + + if (!done && range !== undefined && range.lower !== undefined) { + done = cmp(value.key, range.lower) === -1; + if (done) { + value = undefined; + } + } } return {