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 {QueryTarget, IDBQuery} from "./QueryTarget";
import {IDBRequestError, IDBRequestAttemptError} from "./error"; import {IDBRequestError, IDBRequestAttemptError} from "./error";
import {reqAsPromise} from "./utils"; import {reqAsPromise} from "./utils";
import {Transaction} from "./Transaction"; import {Transaction, IDBKey} from "./Transaction";
import {LogItem} from "../../../logging/LogItem.js"; import {LogItem} from "../../../logging/LogItem.js";
const LOG_REQUESTS = false; const LOG_REQUESTS = false;
@ -126,6 +126,10 @@ class QueryTargetWrapper<T> {
throw new IDBRequestAttemptError("index", this._qt, err, [name]); throw new IDBRequestAttemptError("index", this._qt, err, [name]);
} }
} }
get indexNames(): string[] {
return Array.from(this._qtStore.indexNames);
}
} }
export class Store<T> extends QueryTarget<T> { export class Store<T> extends QueryTarget<T> {
@ -176,7 +180,7 @@ export class Store<T> extends QueryTarget<T> {
return true; return true;
} catch (err) { } catch (err) {
if (err instanceof IDBRequestError) { 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(); err.preventTransactionAbort();
return false; return false;
} else { } else {
@ -191,24 +195,45 @@ export class Store<T> extends QueryTarget<T> {
this._prepareErrorLog(request, log, "delete", keyOrKeyRange, undefined); 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) { if (log) {
log.ensureRefId(); log.ensureRefId();
} }
reqAsPromise(request).catch(err => { reqAsPromise(request).catch(err => {
let keys : IDBKey[] | undefined = undefined;
try { try {
if (!key && value) { if (value) {
key = this._getKey(value); keys = this._getKeys(value);
} else if (key) {
keys = [key];
} }
} catch { } catch (err) {
key = "getKey failed"; 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; 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)) { if (Array.isArray(keyPath)) {
let field: any = value; let field: any = value;
for (const part of keyPath) { for (const part of keyPath) {
@ -221,6 +246,6 @@ export class Store<T> extends QueryTarget<T> {
return field as IDBValidKey; return field as IDBValidKey;
} else { } else {
return value[keyPath] as IDBValidKey; return value[keyPath] as IDBValidKey;
} }
} }
} }

View file

@ -39,12 +39,14 @@ import {AccountDataStore} from "./stores/AccountDataStore";
import {LogItem} from "../../../logging/LogItem.js"; import {LogItem} from "../../../logging/LogItem.js";
import {BaseLogger} from "../../../logging/BaseLogger.js"; import {BaseLogger} from "../../../logging/BaseLogger.js";
export type IDBKey = IDBValidKey | IDBKeyRange;
class WriteErrorInfo { class WriteErrorInfo {
constructor( constructor(
public readonly error: StorageError, public readonly error: StorageError,
public readonly refItem: LogItem | undefined, public readonly refItem: LogItem | undefined,
public readonly operationName: string, 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 // don't log subsequent `AbortError`s
if (error.errcode !== "AbortError" || this._writeErrors.length === 0) { 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); errorGroupItem.set("allowedStoreNames", this._allowedStoreNames);
} }
for (const info of this._writeErrors) { 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) { if (info.refItem) {
item.refDetached(info.refItem); item.refDetached(info.refItem);
} }