2
0
mirror of https://github.com/frappe/books.git synced 2024-11-08 14:50:56 +00:00

fix: capture patch fail errors

- dont notify user
- catch uncaught promise in migration
- prevent unable to acquire conn error
This commit is contained in:
18alantom 2023-04-04 11:51:00 +05:30 committed by Alan
parent b460e96c97
commit 754a1a8e50
7 changed files with 50 additions and 87 deletions

View File

@ -3,11 +3,7 @@ import { DatabaseError } from 'fyo/utils/errors';
import path from 'path';
import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types';
import { getSchemas } from '../../schemas';
import {
databaseMethodSet,
emitMainProcessError,
unlinkIfExists
} from '../helpers';
import { checkFileAccess, databaseMethodSet, unlinkIfExists } from '../helpers';
import patches from '../patches';
import { BespokeQueries } from './bespoke';
import DatabaseCore from './core';
@ -64,8 +60,8 @@ export class DatabaseManager extends DatabaseDemuxBase {
try {
await this.#runPatchesAndMigrate();
} catch (err) {
this.#handleFailedMigration(err, dbPath, copyPath);
} catch (error) {
await this.#handleFailedMigration(error, dbPath, copyPath);
} finally {
await unlinkIfExists(copyPath);
}
@ -78,8 +74,8 @@ export class DatabaseManager extends DatabaseDemuxBase {
) {
await this.db!.close();
if (copyPath) {
await this.#restoreDbCopy(dbPath, copyPath);
if (copyPath && (await checkFileAccess(copyPath))) {
await fs.copyFile(copyPath, dbPath);
}
if (error instanceof Error) {
@ -89,14 +85,6 @@ export class DatabaseManager extends DatabaseDemuxBase {
throw error;
}
async #restoreDbCopy(dbPath: string, copyPath: string) {
try {
await fs.copyFile(copyPath!, dbPath);
} catch (err) {
emitMainProcessError(err);
}
}
async #runPatchesAndMigrate() {
const patchesToExecute = await this.#getPatchesToExecute();
@ -152,8 +140,8 @@ export class DatabaseManager extends DatabaseDemuxBase {
throw new DatabaseError(`invalid bespoke db function ${method}`);
}
// @ts-ignore
const queryFunction: BespokeFunction = BespokeQueries[method];
const queryFunction: BespokeFunction =
BespokeQueries[method as keyof BespokeFunction];
return await queryFunction(this.db!, ...args);
}
@ -180,7 +168,6 @@ export class DatabaseManager extends DatabaseDemuxBase {
try {
await fs.copyFile(src, dest);
} catch (err) {
emitMainProcessError(err);
return null;
}

View File

@ -1,4 +1,4 @@
import { getDefaultMetaFieldValueMap } from '../helpers';
import { emitMainProcessError, getDefaultMetaFieldValueMap } from '../helpers';
import { DatabaseManager } from './manager';
import { FieldValueMap, Patch } from './types';
@ -14,9 +14,13 @@ export async function runPatches(patches: Patch[], dm: DatabaseManager) {
async function runPatch(patch: Patch, dm: DatabaseManager): Promise<boolean> {
try {
await patch.patch.execute(dm);
} catch (err) {
console.error('PATCH FAILED: ', patch.name);
console.error(err);
} catch (error) {
if (!(error instanceof Error)) {
return false;
}
error.message = `Patch Failed: ${patch.name}\n${error.message}`;
emitMainProcessError(error, { patchName: patch.name, notifyUser: false });
return false;
}

View File

@ -205,7 +205,6 @@ export class StockTransferItem extends Doc {
static filters: FiltersMap = {
item: (doc: Doc) => {
let itemNotFor = 'Sales';
console.log(doc.schemaName, doc.isSales);
if (doc.isSales) {
itemNotFor = 'Purchases';
}

View File

@ -50,11 +50,7 @@ import SetupWizard from './pages/SetupWizard/SetupWizard.vue';
import setupInstance from './setup/setupInstance';
import { SetupWizardOptions } from './setup/types';
import './styles/index.css';
import {
connectToDatabase,
dbErrorActionSymbols,
handleDatabaseConnectionError,
} from './utils/db';
import { connectToDatabase, dbErrorActionSymbols } from './utils/db';
import { initializeInstance } from './utils/initialization';
import * as injectionKeys from './utils/injectionKeys';
import { checkForUpdates } from './utils/ipcCalls';
@ -195,57 +191,20 @@ export default defineComponent({
return await this.handleConnectionFailed(error, actionSymbol);
}
const setupComplete = await this.getSetupComplete(filePath);
if (typeof setupComplete === 'object') {
return await this.handleConnectionFailed(
setupComplete.error,
setupComplete.actionSymbol
);
}
const setupComplete = await fyo.getValue(
ModelNameEnum.AccountingSettings,
'setupComplete'
);
if (!setupComplete) {
this.activeScreen = Screen.SetupWizard;
return;
}
await this.initializeInstanceWithErrorHandling(filePath, countryCode);
await initializeInstance(filePath, false, countryCode, fyo);
await updatePrintTemplates(fyo);
await this.setDesk(filePath);
},
async getSetupComplete(dbPath: string) {
try {
return (await fyo.getValue(
ModelNameEnum.AccountingSettings,
'setupComplete'
)) as boolean;
} catch (error) {
if (!(error instanceof Error)) {
throw error;
}
return {
error,
actionSymbol: await handleDatabaseConnectionError(error, dbPath),
};
}
},
async initializeInstanceWithErrorHandling(
dbPath: string,
countryCode: string
) {
try {
return await initializeInstance(dbPath, false, countryCode, fyo);
} catch (error) {
if (!(error instanceof Error)) {
throw error;
}
this.handleConnectionFailed(
error,
await handleDatabaseConnectionError(error, dbPath)
);
}
},
async handleConnectionFailed(error: Error, actionSymbol: symbol) {
await this.showDbSelector();

View File

@ -76,7 +76,8 @@ export function getErrorLogObject(
export async function handleError(
logToConsole: boolean,
error: Error,
more?: Record<string, unknown>
more: Record<string, unknown> = {},
notifyUser: boolean = true
) {
if (logToConsole) {
console.error(error);
@ -86,12 +87,14 @@ export async function handleError(
return;
}
const errorLogObj = getErrorLogObject(error, more ?? {});
const errorLogObj = getErrorLogObject(error, more);
await sendError(errorLogObj);
const toastProps = getToastProps(errorLogObj);
const { showToast } = await import('src/utils/interactive');
await showToast(toastProps);
if (notifyUser) {
const toastProps = getToastProps(errorLogObj);
const { showToast } = await import('src/utils/interactive');
await showToast(toastProps);
}
}
export async function handleErrorWithDialog(

View File

@ -7,11 +7,22 @@ export default function registerIpcRendererListeners() {
ipcRenderer.on(
IPC_CHANNELS.LOG_MAIN_PROCESS_ERROR,
async (_, error, more) => {
if (fyo.store.isDevelopment) {
console.error(error);
if (!(error instanceof Error)) {
throw error;
}
await handleError(true, error as Error, more);
if (!more) {
more = {};
}
if (typeof more !== 'object') {
more = { more };
}
more.isMainProcess = true;
more.notifyUser ??= true;
await handleError(true, error, more, more.notifyUser);
}
);

View File

@ -1,5 +1,11 @@
import { Fyo, t } from 'fyo';
type Conn = {
countryCode: string;
error?: Error;
actionSymbol?: typeof dbErrorActionSymbols[keyof typeof dbErrorActionSymbols];
};
export const dbErrorActionSymbols = {
SelectFile: Symbol('select-file'),
CancelSelection: Symbol('cancel-selection'),
@ -10,12 +16,6 @@ const dbErrors = {
UnableToAcquireConnection: 'Unable to acquire a connection',
} as const;
type Conn = {
countryCode: string;
error?: Error;
actionSymbol?: typeof dbErrorActionSymbols[keyof typeof dbErrorActionSymbols];
};
export async function connectToDatabase(
fyo: Fyo,
dbPath: string,