add Store.tryAdd, which prevent abort on ConstraintError

This commit is contained in:
Bruno Windels 2021-09-21 21:02:39 +02:00
parent 0d486a14f6
commit 12add19c31
3 changed files with 27 additions and 6 deletions

View file

@ -15,7 +15,7 @@ limitations under the License.
*/ */
import {QueryTarget, IDBQuery} from "./QueryTarget"; import {QueryTarget, IDBQuery} from "./QueryTarget";
import {IDBRequestAttemptError} from "./error"; import {IDBRequestError, IDBRequestAttemptError} from "./error";
import {reqAsPromise} from "./utils"; import {reqAsPromise} from "./utils";
import {Transaction} from "./Transaction"; import {Transaction} from "./Transaction";
import {LogItem} from "../../../logging/LogItem.js"; import {LogItem} from "../../../logging/LogItem.js";
@ -169,6 +169,19 @@ export class Store<T> extends QueryTarget<T> {
const request = this._idbStore.add(value); const request = this._idbStore.add(value);
this._prepareErrorLog(request, log, "add", undefined, value); this._prepareErrorLog(request, log, "add", undefined, value);
} }
async tryAdd(value: T, log: LogItem): Promise<boolean> {
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 { delete(keyOrKeyRange: IDBValidKey | IDBKeyRange, log?: LogItem): void {
// ok to not monitor result of request, see comment in `put`. // ok to not monitor result of request, see comment in `put`.

View file

@ -57,10 +57,18 @@ export class IDBError extends StorageError {
} }
export class IDBRequestError extends IDBError { 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 source = request.source;
const cause = request.error; const cause = request.error;
super(message, source, cause); super("IDBRequest failed", source, cause);
this.errorEvent = errorEvent;
}
preventTransactionAbort() {
this.errorEvent.preventDefault();
} }
} }

View file

@ -97,7 +97,7 @@ export function reqAsPromise<T>(req: IDBRequest<T>): Promise<T> {
needsSyncPromise && Promise._flush && Promise._flush(); needsSyncPromise && Promise._flush && Promise._flush();
}); });
req.addEventListener("error", event => { req.addEventListener("error", event => {
const error = new IDBRequestError(event.target as IDBRequest<T>); const error = new IDBRequestError(event);
reject(error); reject(error);
// @ts-ignore // @ts-ignore
needsSyncPromise && Promise._flush && Promise._flush(); needsSyncPromise && Promise._flush && Promise._flush();
@ -143,8 +143,8 @@ type CursorIterator<T, I extends IDBCursor> = (value: I extends IDBCursorWithVal
export function iterateCursor<T, I extends IDBCursor = IDBCursorWithValue>(cursorRequest: IDBRequest<I | null>, processValue: CursorIterator<T, I>): Promise<boolean> { export function iterateCursor<T, I extends IDBCursor = IDBCursorWithValue>(cursorRequest: IDBRequest<I | null>, processValue: CursorIterator<T, I>): Promise<boolean> {
// TODO: does cursor already have a value here?? // TODO: does cursor already have a value here??
return new Promise<boolean>((resolve, reject) => { return new Promise<boolean>((resolve, reject) => {
cursorRequest.onerror = () => { cursorRequest.onerror = event => {
reject(new IDBRequestError(cursorRequest)); reject(new IDBRequestError(event));
// @ts-ignore // @ts-ignore
needsSyncPromise && Promise._flush && Promise._flush(); needsSyncPromise && Promise._flush && Promise._flush();
}; };