From 12add19c314a9d8f708d44f976718913e9adaac4 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 21 Sep 2021 21:02:39 +0200 Subject: [PATCH] add Store.tryAdd, which prevent abort on ConstraintError --- src/matrix/storage/idb/Store.ts | 15 ++++++++++++++- src/matrix/storage/idb/error.ts | 12 ++++++++++-- src/matrix/storage/idb/utils.ts | 6 +++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/matrix/storage/idb/Store.ts b/src/matrix/storage/idb/Store.ts index 42a41ae6..4a018d23 100644 --- a/src/matrix/storage/idb/Store.ts +++ b/src/matrix/storage/idb/Store.ts @@ -15,7 +15,7 @@ limitations under the License. */ import {QueryTarget, IDBQuery} from "./QueryTarget"; -import {IDBRequestAttemptError} from "./error"; +import {IDBRequestError, IDBRequestAttemptError} from "./error"; import {reqAsPromise} from "./utils"; import {Transaction} from "./Transaction"; import {LogItem} from "../../../logging/LogItem.js"; @@ -169,6 +169,19 @@ export class Store extends QueryTarget { const request = this._idbStore.add(value); this._prepareErrorLog(request, log, "add", undefined, value); } + + async tryAdd(value: T, log: LogItem): Promise { + try { + await reqAsPromise(this._idbStore.add(value)); + return true; + } catch (err) { + if (err instanceof IDBRequestError) { + log.log({l: "could not write", id: this._getKey(value), e: err}, log.level.Warn); + err.preventTransactionAbort(); + } + return false; + } + } delete(keyOrKeyRange: IDBValidKey | IDBKeyRange, log?: LogItem): void { // ok to not monitor result of request, see comment in `put`. diff --git a/src/matrix/storage/idb/error.ts b/src/matrix/storage/idb/error.ts index 388ad4c0..fb602168 100644 --- a/src/matrix/storage/idb/error.ts +++ b/src/matrix/storage/idb/error.ts @@ -57,10 +57,18 @@ export class IDBError extends StorageError { } export class IDBRequestError extends IDBError { - constructor(request: IDBRequest, message: string = "IDBRequest failed") { + private errorEvent: Event; + + constructor(errorEvent: Event) { + const request = errorEvent.target as IDBRequest; const source = request.source; const cause = request.error; - super(message, source, cause); + super("IDBRequest failed", source, cause); + this.errorEvent = errorEvent; + } + + preventTransactionAbort() { + this.errorEvent.preventDefault(); } } diff --git a/src/matrix/storage/idb/utils.ts b/src/matrix/storage/idb/utils.ts index f9209f56..a9432139 100644 --- a/src/matrix/storage/idb/utils.ts +++ b/src/matrix/storage/idb/utils.ts @@ -97,7 +97,7 @@ export function reqAsPromise(req: IDBRequest): Promise { needsSyncPromise && Promise._flush && Promise._flush(); }); req.addEventListener("error", event => { - const error = new IDBRequestError(event.target as IDBRequest); + const error = new IDBRequestError(event); reject(error); // @ts-ignore needsSyncPromise && Promise._flush && Promise._flush(); @@ -143,8 +143,8 @@ type CursorIterator = (value: I extends IDBCursorWithVal export function iterateCursor(cursorRequest: IDBRequest, processValue: CursorIterator): Promise { // TODO: does cursor already have a value here?? return new Promise((resolve, reject) => { - cursorRequest.onerror = () => { - reject(new IDBRequestError(cursorRequest)); + cursorRequest.onerror = event => { + reject(new IDBRequestError(event)); // @ts-ignore needsSyncPromise && Promise._flush && Promise._flush(); };