also log index keys for a value when write fails in Store

This commit is contained in:
Bruno Windels 2021-09-22 10:22:52 +02:00
parent a19d93dbef
commit 1963635dd7
2 changed files with 41 additions and 14 deletions

View file

@ -17,7 +17,7 @@ limitations under the License.
import {QueryTarget, IDBQuery} from "./QueryTarget";
import {IDBRequestError, IDBRequestAttemptError} from "./error";
import {reqAsPromise} from "./utils";
import {Transaction} from "./Transaction";
import {Transaction, IDBKey} from "./Transaction";
import {LogItem} from "../../../logging/LogItem.js";
const LOG_REQUESTS = false;
@ -126,6 +126,10 @@ class QueryTargetWrapper<T> {
throw new IDBRequestAttemptError("index", this._qt, err, [name]);
}
}
get indexNames(): string[] {
return Array.from(this._qtStore.indexNames);
}
}
export class Store<T> extends QueryTarget<T> {
@ -176,7 +180,7 @@ export class Store<T> extends QueryTarget<T> {
return true;
} catch (err) {
if (err instanceof IDBRequestError) {
log.log({l: "could not write", id: this._getKey(value), e: err}, log.level.Warn);
log.log({l: "could not write", id: this._getKeys(value), e: err}, log.level.Warn);
err.preventTransactionAbort();
return false;
} else {
@ -191,24 +195,45 @@ export class Store<T> extends QueryTarget<T> {
this._prepareErrorLog(request, log, "delete", keyOrKeyRange, undefined);
}
private _prepareErrorLog(request: IDBRequest, log: LogItem | undefined, operationName: string, key: IDBValidKey | IDBKeyRange | undefined, value: T | undefined) {
private _prepareErrorLog(request: IDBRequest, log: LogItem | undefined, operationName: string, key: IDBKey | undefined, value: T | undefined) {
if (log) {
log.ensureRefId();
}
reqAsPromise(request).catch(err => {
let keys : IDBKey[] | undefined = undefined;
try {
if (!key && value) {
key = this._getKey(value);
if (value) {
keys = this._getKeys(value);
} else if (key) {
keys = [key];
}
} catch {
key = "getKey failed";
} catch (err) {
console.error("_getKeys failed", err);
}
this._transaction.addWriteError(err, log, operationName, key);
this._transaction.addWriteError(err, log, operationName, keys);
});
}
private _getKey(value: T): IDBValidKey {
private _getKeys(value: T): IDBValidKey[] {
const keys: IDBValidKey[] = [];
const {keyPath} = this._idbStore;
try {
keys.push(this._readKeyPath(value, keyPath));
} catch (err) {
console.warn("could not read keyPath", keyPath);
}
for (const indexName of this._idbStore.indexNames) {
try {
const index = this._idbStore.index(indexName);
keys.push(this._readKeyPath(value, index.keyPath));
} catch (err) {
console.warn("could not read index", indexName);
}
}
return keys;
}
private _readKeyPath(value: T, keyPath: string[] | string): IDBValidKey {
if (Array.isArray(keyPath)) {
let field: any = value;
for (const part of keyPath) {
@ -221,6 +246,6 @@ export class Store<T> extends QueryTarget<T> {
return field as IDBValidKey;
} else {
return value[keyPath] as IDBValidKey;
}
}
}
}

View file

@ -39,12 +39,14 @@ import {AccountDataStore} from "./stores/AccountDataStore";
import {LogItem} from "../../../logging/LogItem.js";
import {BaseLogger} from "../../../logging/BaseLogger.js";
export type IDBKey = IDBValidKey | IDBKeyRange;
class WriteErrorInfo {
constructor(
public readonly error: StorageError,
public readonly refItem: LogItem | undefined,
public readonly operationName: string,
public readonly key: IDBValidKey | IDBKeyRange | undefined,
public readonly keys: IDBKey[] | undefined,
) {}
}
@ -192,10 +194,10 @@ export class Transaction {
}
}
addWriteError(error: StorageError, refItem: LogItem | undefined, operationName: string, key: IDBValidKey | IDBKeyRange | undefined) {
addWriteError(error: StorageError, refItem: LogItem | undefined, operationName: string, keys: IDBKey[] | undefined) {
// don't log subsequent `AbortError`s
if (error.errcode !== "AbortError" || this._writeErrors.length === 0) {
this._writeErrors.push(new WriteErrorInfo(error, refItem, operationName, key));
this._writeErrors.push(new WriteErrorInfo(error, refItem, operationName, keys));
}
}
@ -206,7 +208,7 @@ export class Transaction {
errorGroupItem.set("allowedStoreNames", this._allowedStoreNames);
}
for (const info of this._writeErrors) {
errorGroupItem.wrap({l: info.operationName, id: info.key}, item => {
errorGroupItem.wrap({l: info.operationName, id: info.keys}, item => {
if (info.refItem) {
item.refDetached(info.refItem);
}