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 PAUSE_WRITE_ACCESS = 'pause-sql-writes';
const RESUME_WRITE_ACCESS = 'resume-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 { export function initialize(mainSQL: typeof sql): void {
if (initialized) { if (initialized) {
throw new Error('sqlChannels: already initialized!'); throw new Error('sqlChannels: already initialized!');
@@ -35,19 +55,25 @@ export function initialize(mainSQL: typeof sql): void {
sql = mainSQL; sql = mainSQL;
ipcMain.handle(SQL_READ_KEY, (_event, callName, ...args) => { ipcMain.handle(
if (!sql) { SQL_READ_KEY,
throw new Error(`${SQL_READ_KEY}: Not yet initialized!`); wrapResult(function ipcSqlReadHandler(_event, callName, ...args) {
} if (!sql) {
return sql.sqlRead(callName, ...args); throw new Error(`${SQL_READ_KEY}: Not yet initialized!`);
}); }
return sql.sqlRead(callName, ...args);
})
);
ipcMain.handle(SQL_WRITE_KEY, (_event, callName, ...args) => { ipcMain.handle(
if (!sql) { SQL_WRITE_KEY,
throw new Error(`${SQL_WRITE_KEY}: Not yet initialized!`); wrapResult(function ipcSqlWriteHandler(_event, callName, ...args) {
} if (!sql) {
return sql.sqlWrite(callName, ...args); throw new Error(`${SQL_WRITE_KEY}: Not yet initialized!`);
}); }
return sql.sqlWrite(callName, ...args);
})
);
ipcMain.handle(SQL_REMOVE_DB_KEY, () => { ipcMain.handle(SQL_REMOVE_DB_KEY, () => {
if (!sql) { if (!sql) {

View File

@@ -45,7 +45,11 @@ export async function ipcInvoke<T>(
activeJobCount += 1; activeJobCount += 1;
return createTaskWithTimeout(async () => { return createTaskWithTimeout(async () => {
try { 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 { } finally {
activeJobCount -= 1; activeJobCount -= 1;
if (activeJobCount === 0) { if (activeJobCount === 0) {

View File

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