2
0
mirror of https://github.com/frappe/books.git synced 2025-02-08 15:08:29 +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 { ipcRenderer } from 'electron';
import { DEFAULT_COUNTRY_CODE } from 'fyo/utils/consts'; import { DatabaseError, NotImplemented } from 'fyo/utils/errors';
import { SchemaMap } from 'schemas/types'; import { SchemaMap } from 'schemas/types';
import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types'; import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types';
import { DatabaseResponse } from 'utils/ipc/types'; import { DatabaseResponse } from 'utils/ipc/types';
@ -12,101 +12,86 @@ export class DatabaseDemux extends DatabaseDemuxBase {
this.#isElectron = isElectron; 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> { async getSchemaMap(): Promise<SchemaMap> {
let response: DatabaseResponse;
if (this.#isElectron) { if (this.#isElectron) {
response = await ipcRenderer.invoke(IPC_ACTIONS.DB_SCHEMA); return (await this.#handleDBCall(async function dbFunc() {
} else { return await ipcRenderer.invoke(IPC_ACTIONS.DB_SCHEMA);
// TODO: API Call })) as SchemaMap;
response = { error: '', data: undefined };
} }
if (response.error) { throw new NotImplemented();
throw new Error(response.error);
}
return response.data as SchemaMap;
} }
async createNewDatabase( async createNewDatabase(
dbPath: string, dbPath: string,
countryCode?: string countryCode?: string
): Promise<string> { ): Promise<string> {
let response: DatabaseResponse;
if (this.#isElectron) { if (this.#isElectron) {
response = await ipcRenderer.invoke( return (await this.#handleDBCall(async function dbFunc() {
IPC_ACTIONS.DB_CREATE, return await ipcRenderer.invoke(
dbPath, IPC_ACTIONS.DB_CREATE,
countryCode dbPath,
); countryCode
} else { );
// TODO: API Call })) as string;
response = { error: '', data: undefined };
} }
if (response.error) { throw new NotImplemented();
throw new Error(response.error);
}
return (response.data ?? DEFAULT_COUNTRY_CODE) as string;
} }
async connectToDatabase( async connectToDatabase(
dbPath: string, dbPath: string,
countryCode?: string countryCode?: string
): Promise<string> { ): Promise<string> {
let response: DatabaseResponse;
if (this.#isElectron) { if (this.#isElectron) {
response = await ipcRenderer.invoke( return (await this.#handleDBCall(async function dbFunc() {
IPC_ACTIONS.DB_CONNECT, return await ipcRenderer.invoke(
dbPath, IPC_ACTIONS.DB_CONNECT,
countryCode dbPath,
); countryCode
} else { );
// TODO: API Call })) as string;
response = { error: '', data: undefined };
} }
if (response.error) { throw new NotImplemented();
throw new Error(response.error);
}
return (response.data ?? DEFAULT_COUNTRY_CODE) as string;
} }
async call(method: DatabaseMethod, ...args: unknown[]): Promise<unknown> { async call(method: DatabaseMethod, ...args: unknown[]): Promise<unknown> {
let response: DatabaseResponse;
if (this.#isElectron) { if (this.#isElectron) {
response = await ipcRenderer.invoke(IPC_ACTIONS.DB_CALL, method, ...args); return (await this.#handleDBCall(async function dbFunc() {
} else { return await ipcRenderer.invoke(IPC_ACTIONS.DB_CALL, method, ...args);
// TODO: API Call })) as unknown;
response = { error: '', data: undefined };
} }
if (response.error) { throw new NotImplemented();
throw new Error(response.error);
}
return response.data;
} }
async callBespoke(method: string, ...args: unknown[]): Promise<unknown> { async callBespoke(method: string, ...args: unknown[]): Promise<unknown> {
let response: DatabaseResponse;
if (this.#isElectron) { if (this.#isElectron) {
response = await ipcRenderer.invoke( return (await this.#handleDBCall(async function dbFunc() {
IPC_ACTIONS.DB_BESPOKE, return await ipcRenderer.invoke(
method, IPC_ACTIONS.DB_BESPOKE,
...args method,
); ...args
} else { );
// TODO: API Call })) as unknown;
response = { error: '', data: undefined };
} }
if (response.error) { throw new NotImplemented();
throw new Error(response.error);
}
return response.data;
} }
} }

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 ValueError extends ValidationError {}
export class ConflictError extends ValidationError {} export class ConflictError extends ValidationError {}
export class InvalidFieldError extends ValidationError {} export class InvalidFieldError extends ValidationError {}

View File

@ -2,6 +2,7 @@ import { constants } from 'fs';
import fs from 'fs/promises'; import fs from 'fs/promises';
import { ConfigFile, ConfigKeys } from 'fyo/core/types'; import { ConfigFile, ConfigKeys } from 'fyo/core/types';
import config from 'utils/config'; import config from 'utils/config';
import { DatabaseResponse } from 'utils/ipc/types';
interface ConfigFilesWithModified extends ConfigFile { interface ConfigFilesWithModified extends ConfigFile {
modified: string; modified: string;
@ -44,3 +45,19 @@ export async function getConfigFilesWithModified(files: ConfigFile[]) {
return filesWithModified; 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 databaseManager from '../backend/database/manager';
import { Main } from '../main'; import { Main } from '../main';
import { DatabaseMethod } from '../utils/db/types'; import { DatabaseMethod } from '../utils/db/types';
import { DatabaseResponse } from '../utils/ipc/types';
import { IPC_ACTIONS } from '../utils/messages'; import { IPC_ACTIONS } from '../utils/messages';
import { getUrlAndTokenString, sendError } from './contactMothership'; import { getUrlAndTokenString, sendError } from './contactMothership';
import { getLanguageMap } from './getLanguageMap'; import { getLanguageMap } from './getLanguageMap';
import { import {
getConfigFilesWithModified, getConfigFilesWithModified,
getErrorHandledReponse,
setAndGetCleanedConfigFiles, setAndGetCleanedConfigFiles,
} from './helpers'; } from './helpers';
import { saveHtmlAsPdf } from './saveHtmlAsPdf'; import { saveHtmlAsPdf } from './saveHtmlAsPdf';
@ -136,68 +136,42 @@ export default function registerIpcMainActionListeners(main: Main) {
ipcMain.handle( ipcMain.handle(
IPC_ACTIONS.DB_CREATE, IPC_ACTIONS.DB_CREATE,
async (_, dbPath: string, countryCode: string) => { async (_, dbPath: string, countryCode: string) => {
const response: DatabaseResponse = { error: '', data: undefined }; return await getErrorHandledReponse(async function dbFunc() {
try { return await databaseManager.createNewDatabase(dbPath, countryCode);
response.data = await databaseManager.createNewDatabase( });
dbPath,
countryCode
);
} catch (error) {
response.error = (error as Error).toString();
}
return response;
} }
); );
ipcMain.handle( ipcMain.handle(
IPC_ACTIONS.DB_CONNECT, IPC_ACTIONS.DB_CONNECT,
async (_, dbPath: string, countryCode?: string) => { async (_, dbPath: string, countryCode?: string) => {
const response: DatabaseResponse = { error: '', data: undefined }; return await getErrorHandledReponse(async function dbFunc() {
try { return await databaseManager.connectToDatabase(dbPath, countryCode);
response.data = await databaseManager.connectToDatabase( });
dbPath,
countryCode
);
} catch (error) {
response.error = (error as Error).toString();
}
return response;
} }
); );
ipcMain.handle( ipcMain.handle(
IPC_ACTIONS.DB_CALL, IPC_ACTIONS.DB_CALL,
async (_, method: DatabaseMethod, ...args: unknown[]) => { async (_, method: DatabaseMethod, ...args: unknown[]) => {
const response: DatabaseResponse = { error: '', data: undefined }; return await getErrorHandledReponse(async function dbFunc() {
try { return await databaseManager.call(method, ...args);
response.data = await databaseManager.call(method, ...args); });
} catch (error) {
response.error = (error as Error).toString();
}
return response;
} }
); );
ipcMain.handle( ipcMain.handle(
IPC_ACTIONS.DB_BESPOKE, IPC_ACTIONS.DB_BESPOKE,
async (_, method: string, ...args: unknown[]) => { async (_, method: string, ...args: unknown[]) => {
const response: DatabaseResponse = { error: '', data: undefined }; return await getErrorHandledReponse(async function dbFunc() {
try { return await databaseManager.callBespoke(method, ...args);
response.data = await databaseManager.callBespoke(method, ...args); });
} catch (error) {
response.error = (error as Error).toString();
}
return response;
} }
); );
ipcMain.handle(IPC_ACTIONS.DB_SCHEMA, async (_) => { ipcMain.handle(IPC_ACTIONS.DB_SCHEMA, async (_) => {
const response: DatabaseResponse = { error: '', data: undefined }; return await getErrorHandledReponse(async function dbFunc() {
response.data = await databaseManager.getSchemaMap(); return await databaseManager.getSchemaMap();
return response; });
}); });
} }

View File

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