Prefix sql read/write errors with method name

Co-authored-by: Jamie Kyle <113370520+jamiebuilds-signal@users.noreply.github.com>
This commit is contained in:
Fedor Indutny
2025-05-13 12:04:13 -07:00
committed by GitHub
parent 56151d870c
commit 1279278ccc
3 changed files with 59 additions and 22 deletions

View File

@@ -27,6 +27,26 @@ const ERASE_SQL_KEY = 'erase-sql-key';
const PAUSE_WRITE_ACCESS = 'pause-sql-writes';
const RESUME_WRITE_ACCESS = 'resume-sql-writes';
function wrapResult<Params extends Array<unknown>, T>(
fn: (...params: Params) => Promise<T>
): (
...params: Params
) => Promise<{ ok: true; value: T } | { ok: false; error: Error }> {
return async function wrappedIpcSqlMethod(...params) {
try {
return {
ok: true,
value: await fn(...params),
};
} catch (error) {
return {
ok: false,
error,
};
}
};
}
export function initialize(mainSQL: typeof sql): void {
if (initialized) {
throw new Error('sqlChannels: already initialized!');
@@ -35,19 +55,25 @@ export function initialize(mainSQL: typeof sql): void {
sql = mainSQL;
ipcMain.handle(SQL_READ_KEY, (_event, callName, ...args) => {
if (!sql) {
throw new Error(`${SQL_READ_KEY}: Not yet initialized!`);
}
return sql.sqlRead(callName, ...args);
});
ipcMain.handle(
SQL_READ_KEY,
wrapResult(function ipcSqlReadHandler(_event, callName, ...args) {
if (!sql) {
throw new Error(`${SQL_READ_KEY}: Not yet initialized!`);
}
return sql.sqlRead(callName, ...args);
})
);
ipcMain.handle(SQL_WRITE_KEY, (_event, callName, ...args) => {
if (!sql) {
throw new Error(`${SQL_WRITE_KEY}: Not yet initialized!`);
}
return sql.sqlWrite(callName, ...args);
});
ipcMain.handle(
SQL_WRITE_KEY,
wrapResult(function ipcSqlWriteHandler(_event, callName, ...args) {
if (!sql) {
throw new Error(`${SQL_WRITE_KEY}: Not yet initialized!`);
}
return sql.sqlWrite(callName, ...args);
})
);
ipcMain.handle(SQL_REMOVE_DB_KEY, () => {
if (!sql) {

View File

@@ -45,7 +45,11 @@ export async function ipcInvoke<T>(
activeJobCount += 1;
return createTaskWithTimeout(async () => {
try {
return await ipcRenderer.invoke(channel, name, ...args);
const result = await ipcRenderer.invoke(channel, name, ...args);
if (!result.ok) {
throw result.error;
}
return result.value;
} finally {
activeJobCount -= 1;
if (activeJobCount === 0) {

View File

@@ -83,7 +83,8 @@ export type WrappedWorkerResponse =
}>
| WrappedWorkerLogEntry;
type PromisePair<T> = {
type ResponseEntry<T> = {
errorId: string;
resolve: (response: T) => void;
reject: (error: Error) => void;
};
@@ -129,7 +130,7 @@ export class MainSQL {
#logger?: LoggerType;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
#onResponse = new Map<number, PromisePair<any>>();
#onResponse = new Map<number, ResponseEntry<any>>();
#shouldTimeQueries = false;
#shouldTrackQueryStats = false;
@@ -323,7 +324,9 @@ export class MainSQL {
entry: PoolEntry,
request: WorkerRequest
): Promise<Response> {
let errorId: string = request.type;
if (request.type === 'sqlCall:read' || request.type === 'sqlCall:write') {
errorId = `${request.type}(${request.method})`;
if (this.#onReady) {
await this.#onReady;
}
@@ -338,7 +341,11 @@ export class MainSQL {
this.#seq = (this.#seq + 1) >>> 0;
const { promise: result, resolve, reject } = explodePromise<Response>();
this.#onResponse.set(seq, { resolve, reject });
this.#onResponse.set(seq, {
errorId,
resolve,
reject,
});
const wrappedRequest: WrappedWorkerRequest = {
seq,
@@ -467,21 +474,21 @@ export class MainSQL {
const { seq, error, errorKind, response } = wrappedResponse;
const pair = this.#onResponse.get(seq);
const entry = this.#onResponse.get(seq);
this.#onResponse.delete(seq);
if (!pair) {
if (!entry) {
throw new Error(`Unexpected worker response with seq: ${seq}`);
}
if (error) {
const errorObj = new Error(error.message);
errorObj.stack = error.stack;
const errorObj = new Error(`${entry.errorId}: ${error.message}`);
errorObj.stack = `${entry.errorId}: ${error.stack}`;
errorObj.name = error.name;
this.#onError(errorKind ?? SqliteErrorKind.Unknown, errorObj);
pair.reject(errorObj);
entry.reject(errorObj);
} else {
pair.resolve(response);
entry.resolve(response);
}
});