2
0
mirror of https://github.com/frappe/books.git synced 2025-02-02 03:58:26 +00:00

incr: improve db call error handling

This commit is contained in:
18alantom 2022-05-20 15:36:38 +05:30
parent 969ec5d7cd
commit ca5514417e
5 changed files with 90 additions and 106 deletions

View File

@ -1,5 +1,5 @@
import { ipcRenderer } from 'electron';
import { DEFAULT_COUNTRY_CODE } from 'fyo/utils/consts';
import { DatabaseError, NotImplemented } from 'fyo/utils/errors';
import { SchemaMap } from 'schemas/types';
import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types';
import { DatabaseResponse } from 'utils/ipc/types';
@ -12,101 +12,86 @@ export class DatabaseDemux extends DatabaseDemuxBase {
this.#isElectron = isElectron;
}
async #handleDBCall(func: () => Promise<DatabaseResponse>): Promise<unknown> {
const response = await func();
if (response.error?.name) {
const { name, message, stack } = response.error;
const dberror = new DatabaseError(message);
dberror.name = name;
dberror.stack = stack;
throw dberror;
}
return response.data;
}
async getSchemaMap(): Promise<SchemaMap> {
let response: DatabaseResponse;
if (this.#isElectron) {
response = await ipcRenderer.invoke(IPC_ACTIONS.DB_SCHEMA);
} else {
// TODO: API Call
response = { error: '', data: undefined };
return (await this.#handleDBCall(async function dbFunc() {
return await ipcRenderer.invoke(IPC_ACTIONS.DB_SCHEMA);
})) as SchemaMap;
}
if (response.error) {
throw new Error(response.error);
}
return response.data as SchemaMap;
throw new NotImplemented();
}
async createNewDatabase(
dbPath: string,
countryCode?: string
): Promise<string> {
let response: DatabaseResponse;
if (this.#isElectron) {
response = await ipcRenderer.invoke(
IPC_ACTIONS.DB_CREATE,
dbPath,
countryCode
);
} else {
// TODO: API Call
response = { error: '', data: undefined };
return (await this.#handleDBCall(async function dbFunc() {
return await ipcRenderer.invoke(
IPC_ACTIONS.DB_CREATE,
dbPath,
countryCode
);
})) as string;
}
if (response.error) {
throw new Error(response.error);
}
return (response.data ?? DEFAULT_COUNTRY_CODE) as string;
throw new NotImplemented();
}
async connectToDatabase(
dbPath: string,
countryCode?: string
): Promise<string> {
let response: DatabaseResponse;
if (this.#isElectron) {
response = await ipcRenderer.invoke(
IPC_ACTIONS.DB_CONNECT,
dbPath,
countryCode
);
} else {
// TODO: API Call
response = { error: '', data: undefined };
return (await this.#handleDBCall(async function dbFunc() {
return await ipcRenderer.invoke(
IPC_ACTIONS.DB_CONNECT,
dbPath,
countryCode
);
})) as string;
}
if (response.error) {
throw new Error(response.error);
}
return (response.data ?? DEFAULT_COUNTRY_CODE) as string;
throw new NotImplemented();
}
async call(method: DatabaseMethod, ...args: unknown[]): Promise<unknown> {
let response: DatabaseResponse;
if (this.#isElectron) {
response = await ipcRenderer.invoke(IPC_ACTIONS.DB_CALL, method, ...args);
} else {
// TODO: API Call
response = { error: '', data: undefined };
return (await this.#handleDBCall(async function dbFunc() {
return await ipcRenderer.invoke(IPC_ACTIONS.DB_CALL, method, ...args);
})) as unknown;
}
if (response.error) {
throw new Error(response.error);
}
return response.data;
throw new NotImplemented();
}
async callBespoke(method: string, ...args: unknown[]): Promise<unknown> {
let response: DatabaseResponse;
if (this.#isElectron) {
response = await ipcRenderer.invoke(
IPC_ACTIONS.DB_BESPOKE,
method,
...args
);
} else {
// TODO: API Call
response = { error: '', data: undefined };
return (await this.#handleDBCall(async function dbFunc() {
return await ipcRenderer.invoke(
IPC_ACTIONS.DB_BESPOKE,
method,
...args
);
})) as unknown;
}
if (response.error) {
throw new Error(response.error);
}
return response.data;
throw new NotImplemented();
}
}

View File

@ -78,6 +78,14 @@ export class CannotCommitError extends DatabaseError {
}
}
export class NotImplemented extends BaseError {
constructor() {
super(501, '');
this.label = t`Not Implemented`;
this.name = 'NotImplemented';
}
}
export class ValueError extends ValidationError {}
export class ConflictError extends ValidationError {}
export class InvalidFieldError extends ValidationError {}

View File

@ -2,6 +2,7 @@ import { constants } from 'fs';
import fs from 'fs/promises';
import { ConfigFile, ConfigKeys } from 'fyo/core/types';
import config from 'utils/config';
import { DatabaseResponse } from 'utils/ipc/types';
interface ConfigFilesWithModified extends ConfigFile {
modified: string;
@ -44,3 +45,19 @@ export async function getConfigFilesWithModified(files: ConfigFile[]) {
return filesWithModified;
}
export async function getErrorHandledReponse(func: () => Promise<unknown>) {
const response: DatabaseResponse = {};
try {
response.data = await func();
} catch (err) {
response.error = {
name: (err as Error).name,
message: (err as Error).message,
stack: (err as Error).stack,
};
}
return response;
}

View File

@ -5,12 +5,12 @@ import path from 'path';
import databaseManager from '../backend/database/manager';
import { Main } from '../main';
import { DatabaseMethod } from '../utils/db/types';
import { DatabaseResponse } from '../utils/ipc/types';
import { IPC_ACTIONS } from '../utils/messages';
import { getUrlAndTokenString, sendError } from './contactMothership';
import { getLanguageMap } from './getLanguageMap';
import {
getConfigFilesWithModified,
getErrorHandledReponse,
setAndGetCleanedConfigFiles,
} from './helpers';
import { saveHtmlAsPdf } from './saveHtmlAsPdf';
@ -136,68 +136,42 @@ export default function registerIpcMainActionListeners(main: Main) {
ipcMain.handle(
IPC_ACTIONS.DB_CREATE,
async (_, dbPath: string, countryCode: string) => {
const response: DatabaseResponse = { error: '', data: undefined };
try {
response.data = await databaseManager.createNewDatabase(
dbPath,
countryCode
);
} catch (error) {
response.error = (error as Error).toString();
}
return response;
return await getErrorHandledReponse(async function dbFunc() {
return await databaseManager.createNewDatabase(dbPath, countryCode);
});
}
);
ipcMain.handle(
IPC_ACTIONS.DB_CONNECT,
async (_, dbPath: string, countryCode?: string) => {
const response: DatabaseResponse = { error: '', data: undefined };
try {
response.data = await databaseManager.connectToDatabase(
dbPath,
countryCode
);
} catch (error) {
response.error = (error as Error).toString();
}
return response;
return await getErrorHandledReponse(async function dbFunc() {
return await databaseManager.connectToDatabase(dbPath, countryCode);
});
}
);
ipcMain.handle(
IPC_ACTIONS.DB_CALL,
async (_, method: DatabaseMethod, ...args: unknown[]) => {
const response: DatabaseResponse = { error: '', data: undefined };
try {
response.data = await databaseManager.call(method, ...args);
} catch (error) {
response.error = (error as Error).toString();
}
return response;
return await getErrorHandledReponse(async function dbFunc() {
return await databaseManager.call(method, ...args);
});
}
);
ipcMain.handle(
IPC_ACTIONS.DB_BESPOKE,
async (_, method: string, ...args: unknown[]) => {
const response: DatabaseResponse = { error: '', data: undefined };
try {
response.data = await databaseManager.callBespoke(method, ...args);
} catch (error) {
response.error = (error as Error).toString();
}
return response;
return await getErrorHandledReponse(async function dbFunc() {
return await databaseManager.callBespoke(method, ...args);
});
}
);
ipcMain.handle(IPC_ACTIONS.DB_SCHEMA, async (_) => {
const response: DatabaseResponse = { error: '', data: undefined };
response.data = await databaseManager.getSchemaMap();
return response;
return await getErrorHandledReponse(async function dbFunc() {
return await databaseManager.getSchemaMap();
});
});
}

View File

@ -1,4 +1,4 @@
export interface DatabaseResponse {
error: string;
data?: unknown;
error?: { message: string; name: string; stack?: string };
}