mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-24 12:04:57 +01:00
Add initial stab at annotating QueryTarget
This commit is contained in:
parent
fefa15cd85
commit
1d5b105c34
@ -15,13 +15,18 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {iterateCursor, reqAsPromise} from "./utils";
|
import {iterateCursor, reqAsPromise} from "./utils";
|
||||||
|
import {QueryTargetWrapper} from "./Store.js"
|
||||||
|
|
||||||
export class QueryTarget {
|
type Reducer<A,B> = (acc: B, val: A) => B
|
||||||
constructor(target) {
|
|
||||||
|
export class QueryTarget<T> {
|
||||||
|
private _target: QueryTargetWrapper
|
||||||
|
|
||||||
|
constructor(target: QueryTargetWrapper) {
|
||||||
this._target = target;
|
this._target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
_openCursor(range, direction) {
|
_openCursor(range?: IDBKeyRange, direction?: IDBCursorDirection) {
|
||||||
if (range && direction) {
|
if (range && direction) {
|
||||||
return this._target.openCursor(range, direction);
|
return this._target.openCursor(range, direction);
|
||||||
} else if (range) {
|
} else if (range) {
|
||||||
@ -33,19 +38,19 @@ export class QueryTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
supports(methodName) {
|
supports(methodName: string): boolean {
|
||||||
return this._target.supports(methodName);
|
return this._target.supports(methodName);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(key) {
|
get(key: IDBValidKey): Promise<T> {
|
||||||
return reqAsPromise(this._target.get(key));
|
return reqAsPromise(this._target.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
getKey(key) {
|
getKey(key: IDBValidKey): Promise<IDBValidKey | undefined> {
|
||||||
if (this._target.supports("getKey")) {
|
if (this._target.supports("getKey")) {
|
||||||
return reqAsPromise(this._target.getKey(key));
|
return reqAsPromise(this._target.getKey(key));
|
||||||
} else {
|
} else {
|
||||||
return reqAsPromise(this._target.get(key)).then(value => {
|
return reqAsPromise<T>(this._target.get(key)).then(value => {
|
||||||
if (value) {
|
if (value) {
|
||||||
return value[this._target.keyPath];
|
return value[this._target.keyPath];
|
||||||
}
|
}
|
||||||
@ -53,57 +58,57 @@ export class QueryTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reduce(range, reducer, initialValue) {
|
reduce<B>(range: IDBKeyRange, reducer: Reducer<T,B>, initialValue: B): Promise<boolean> {
|
||||||
return this._reduce(range, reducer, initialValue, "next");
|
return this._reduce(range, reducer, initialValue, "next");
|
||||||
}
|
}
|
||||||
|
|
||||||
reduceReverse(range, reducer, initialValue) {
|
reduceReverse<B>(range: IDBKeyRange, reducer: Reducer<T,B>, initialValue: B): Promise<boolean> {
|
||||||
return this._reduce(range, reducer, initialValue, "prev");
|
return this._reduce(range, reducer, initialValue, "prev");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectLimit(range, amount) {
|
selectLimit(range: IDBKeyRange, amount: number): Promise<T[]> {
|
||||||
return this._selectLimit(range, amount, "next");
|
return this._selectLimit(range, amount, "next");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectLimitReverse(range, amount) {
|
selectLimitReverse(range: IDBKeyRange, amount: number): Promise<T[]> {
|
||||||
return this._selectLimit(range, amount, "prev");
|
return this._selectLimit(range, amount, "prev");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectWhile(range, predicate) {
|
selectWhile(range: IDBKeyRange, predicate: (v: T) => boolean): Promise<T[]> {
|
||||||
return this._selectWhile(range, predicate, "next");
|
return this._selectWhile(range, predicate, "next");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectWhileReverse(range, predicate) {
|
selectWhileReverse(range: IDBKeyRange, predicate: (v: T) => boolean): Promise<T[]> {
|
||||||
return this._selectWhile(range, predicate, "prev");
|
return this._selectWhile(range, predicate, "prev");
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectAll(range, direction) {
|
async selectAll(range: IDBKeyRange, direction: IDBCursorDirection): Promise<T[]> {
|
||||||
const cursor = this._openCursor(range, direction);
|
const cursor = this._openCursor(range, direction);
|
||||||
const results = [];
|
const results: T[] = [];
|
||||||
await iterateCursor(cursor, (value) => {
|
await iterateCursor<T>(cursor, (value) => {
|
||||||
results.push(value);
|
results.push(value);
|
||||||
return {done: false};
|
return {done: false};
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectFirst(range) {
|
selectFirst(range: IDBKeyRange): Promise<T | undefined> {
|
||||||
return this._find(range, () => true, "next");
|
return this._find(range, () => true, "next");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectLast(range) {
|
selectLast(range: IDBKeyRange): Promise<T | undefined> {
|
||||||
return this._find(range, () => true, "prev");
|
return this._find(range, () => true, "prev");
|
||||||
}
|
}
|
||||||
|
|
||||||
find(range, predicate) {
|
find(range: IDBKeyRange, predicate: (v: T) => boolean): Promise<T | undefined> {
|
||||||
return this._find(range, predicate, "next");
|
return this._find(range, predicate, "next");
|
||||||
}
|
}
|
||||||
|
|
||||||
findReverse(range, predicate) {
|
findReverse(range: IDBKeyRange, predicate: (v : T) => boolean): Promise<T | undefined> {
|
||||||
return this._find(range, predicate, "prev");
|
return this._find(range, predicate, "prev");
|
||||||
}
|
}
|
||||||
|
|
||||||
async findMaxKey(range) {
|
async findMaxKey(range: IDBKeyRange): Promise<IDBValidKey | undefined> {
|
||||||
const cursor = this._target.openKeyCursor(range, "prev");
|
const cursor = this._target.openKeyCursor(range, "prev");
|
||||||
let maxKey;
|
let maxKey;
|
||||||
await iterateCursor(cursor, (_, key) => {
|
await iterateCursor(cursor, (_, key) => {
|
||||||
@ -114,14 +119,14 @@ export class QueryTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async iterateValues(range, callback) {
|
async iterateValues(range: IDBKeyRange, callback: (val: T, key: IDBValidKey, cur: IDBCursorWithValue) => boolean) {
|
||||||
const cursor = this._target.openCursor(range, "next");
|
const cursor = this._target.openCursor(range, "next");
|
||||||
await iterateCursor(cursor, (value, key, cur) => {
|
await iterateCursor<T>(cursor, (value, key, cur) => {
|
||||||
return {done: callback(value, key, cur)};
|
return {done: callback(value, key, cur)};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async iterateKeys(range, callback) {
|
async iterateKeys(range: IDBKeyRange, callback: (key: IDBValidKey, cur: IDBCursorWithValue) => boolean) {
|
||||||
const cursor = this._target.openKeyCursor(range, "next");
|
const cursor = this._target.openKeyCursor(range, "next");
|
||||||
await iterateCursor(cursor, (_, key, cur) => {
|
await iterateCursor(cursor, (_, key, cur) => {
|
||||||
return {done: callback(key, cur)};
|
return {done: callback(key, cur)};
|
||||||
@ -134,7 +139,7 @@ export class QueryTarget {
|
|||||||
* If the callback returns true, the search is halted and callback won't be called again.
|
* If the callback returns true, the search is halted and callback won't be called again.
|
||||||
* `callback` is called with the same instances of the key as given in `keys`, so direct comparison can be used.
|
* `callback` is called with the same instances of the key as given in `keys`, so direct comparison can be used.
|
||||||
*/
|
*/
|
||||||
async findExistingKeys(keys, backwards, callback) {
|
async findExistingKeys(keys: IDBValidKey[], backwards: boolean, callback: (key: IDBValidKey, found: boolean) => boolean) {
|
||||||
const direction = backwards ? "prev" : "next";
|
const direction = backwards ? "prev" : "next";
|
||||||
const compareKeys = (a, b) => backwards ? -indexedDB.cmp(a, b) : indexedDB.cmp(a, b);
|
const compareKeys = (a, b) => backwards ? -indexedDB.cmp(a, b) : indexedDB.cmp(a, b);
|
||||||
const sortedKeys = keys.slice().sort(compareKeys);
|
const sortedKeys = keys.slice().sort(compareKeys);
|
||||||
@ -154,7 +159,10 @@ export class QueryTarget {
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
const done = consumerDone || i >= sortedKeys.length;
|
const done = consumerDone || i >= sortedKeys.length;
|
||||||
const jumpTo = !done && sortedKeys[i];
|
let jumpTo;
|
||||||
|
if (!done) {
|
||||||
|
jumpTo = sortedKeys[i];
|
||||||
|
}
|
||||||
return {done, jumpTo};
|
return {done, jumpTo};
|
||||||
});
|
});
|
||||||
// report null for keys we didn't to at the end
|
// report null for keys we didn't to at the end
|
||||||
@ -164,25 +172,25 @@ export class QueryTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_reduce(range, reducer, initialValue, direction) {
|
_reduce<B>(range: IDBKeyRange, reducer: (reduced: B, value: T) => B, initialValue: B, direction: IDBCursorDirection): Promise<boolean> {
|
||||||
let reducedValue = initialValue;
|
let reducedValue = initialValue;
|
||||||
const cursor = this._openCursor(range, direction);
|
const cursor = this._openCursor(range, direction);
|
||||||
return iterateCursor(cursor, (value) => {
|
return iterateCursor<T>(cursor, (value) => {
|
||||||
reducedValue = reducer(reducedValue, value);
|
reducedValue = reducer(reducedValue, value);
|
||||||
return {done: false};
|
return {done: false};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_selectLimit(range, amount, direction) {
|
_selectLimit(range: IDBKeyRange, amount: number, direction: IDBCursorDirection): Promise<T[]> {
|
||||||
return this._selectUntil(range, (results) => {
|
return this._selectUntil(range, (results) => {
|
||||||
return results.length === amount;
|
return results.length === amount;
|
||||||
}, direction);
|
}, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _selectUntil(range, predicate, direction) {
|
async _selectUntil(range: IDBKeyRange, predicate: (vs: T[], v: T) => boolean, direction: IDBCursorDirection): Promise<T[]> {
|
||||||
const cursor = this._openCursor(range, direction);
|
const cursor = this._openCursor(range, direction);
|
||||||
const results = [];
|
const results: T[] = [];
|
||||||
await iterateCursor(cursor, (value) => {
|
await iterateCursor<T>(cursor, (value) => {
|
||||||
results.push(value);
|
results.push(value);
|
||||||
return {done: predicate(results, value)};
|
return {done: predicate(results, value)};
|
||||||
});
|
});
|
||||||
@ -190,10 +198,10 @@ export class QueryTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allows you to fetch one too much that won't get added when the predicate fails
|
// allows you to fetch one too much that won't get added when the predicate fails
|
||||||
async _selectWhile(range, predicate, direction) {
|
async _selectWhile(range: IDBKeyRange, predicate: (v: T) => boolean, direction: IDBCursorDirection): Promise<T[]> {
|
||||||
const cursor = this._openCursor(range, direction);
|
const cursor = this._openCursor(range, direction);
|
||||||
const results = [];
|
const results: T[] = [];
|
||||||
await iterateCursor(cursor, (value) => {
|
await iterateCursor<T>(cursor, (value) => {
|
||||||
const passesPredicate = predicate(value);
|
const passesPredicate = predicate(value);
|
||||||
if (passesPredicate) {
|
if (passesPredicate) {
|
||||||
results.push(value);
|
results.push(value);
|
||||||
@ -203,18 +211,18 @@ export class QueryTarget {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
async iterateWhile(range, predicate) {
|
async iterateWhile(range: IDBKeyRange, predicate: (v: T) => boolean) {
|
||||||
const cursor = this._openCursor(range, "next");
|
const cursor = this._openCursor(range, "next");
|
||||||
await iterateCursor(cursor, (value) => {
|
await iterateCursor<T>(cursor, (value) => {
|
||||||
const passesPredicate = predicate(value);
|
const passesPredicate = predicate(value);
|
||||||
return {done: !passesPredicate};
|
return {done: !passesPredicate};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async _find(range, predicate, direction) {
|
async _find(range: IDBKeyRange, predicate: (v: T) => boolean, direction: IDBCursorDirection): Promise<T | undefined> {
|
||||||
const cursor = this._openCursor(range, direction);
|
const cursor = this._openCursor(range, direction);
|
||||||
let result;
|
let result;
|
||||||
const found = await iterateCursor(cursor, (value) => {
|
const found = await iterateCursor<T>(cursor, (value) => {
|
||||||
const found = predicate(value);
|
const found = predicate(value);
|
||||||
if (found) {
|
if (found) {
|
||||||
result = value;
|
result = value;
|
||||||
|
@ -124,7 +124,7 @@ export function txnAsPromise(txn): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
type CursorIterator<T> = (value: T, key?: IDBValidKey, cursor?: IDBCursorWithValue) => { done: boolean, jumpTo?: IDBValidKey }
|
type CursorIterator<T> = (value: T, key: IDBValidKey, cursor: IDBCursorWithValue) => { done: boolean, jumpTo?: IDBValidKey }
|
||||||
|
|
||||||
export function iterateCursor<T>(cursorRequest: IDBRequest<IDBCursorWithValue>, processValue: CursorIterator<T>): Promise<boolean> {
|
export function iterateCursor<T>(cursorRequest: IDBRequest<IDBCursorWithValue>, processValue: CursorIterator<T>): Promise<boolean> {
|
||||||
// TODO: does cursor already have a value here??
|
// TODO: does cursor already have a value here??
|
||||||
|
Loading…
Reference in New Issue
Block a user