2
0
mirror of https://github.com/frappe/books.git synced 2024-11-10 15:50:56 +00:00
books/fyo/core/dbHandler.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

223 lines
5.9 KiB
TypeScript
Raw Normal View History

import { SingleValue } from 'backend/database/types';
import { Fyo } from 'fyo';
import { DatabaseDemux } from 'fyo/demux/db';
2022-04-18 05:07:36 +00:00
import { Field, RawValue, SchemaMap } from 'schemas/types';
import { getMapFromList } from 'utils';
import { DatabaseBase, DatabaseDemuxBase, GetAllOptions } from 'utils/db/types';
2022-04-18 05:07:36 +00:00
import { Converter } from './converter';
import {
DatabaseDemuxConstructor,
DocValue,
DocValueMap,
RawValueMap,
} from './types';
2022-03-22 09:28:36 +00:00
// Return types of Bespoke Queries
type TopExpenses = { account: string; total: number }[];
type TotalOutstanding = { total: number; outstanding: number };
type Cashflow = { inflow: number; outflow: number; 'month-year': string }[];
2022-03-31 09:04:30 +00:00
export class DatabaseHandler extends DatabaseBase {
#fyo: Fyo;
2022-04-18 05:07:36 +00:00
converter: Converter;
#demux: DatabaseDemuxBase;
dbPath?: string;
schemaMap: Readonly<SchemaMap> = {};
2022-04-18 05:07:36 +00:00
fieldValueMap: Record<string, Record<string, Field>> = {};
2022-03-22 09:28:36 +00:00
constructor(fyo: Fyo, Demux?: DatabaseDemuxConstructor) {
2022-03-31 09:04:30 +00:00
super();
this.#fyo = fyo;
this.converter = new Converter(this, this.#fyo);
if (Demux !== undefined) {
this.#demux = new Demux(fyo.isElectron);
} else {
this.#demux = new DatabaseDemux(fyo.isElectron);
}
2022-03-22 09:28:36 +00:00
}
async createNewDatabase(dbPath: string, countryCode: string) {
countryCode = await this.#demux.createNewDatabase(dbPath, countryCode);
await this.init();
this.dbPath = dbPath;
return countryCode;
2022-03-22 09:28:36 +00:00
}
2022-03-31 09:04:30 +00:00
async connectToDatabase(dbPath: string, countryCode?: string) {
countryCode = await this.#demux.connectToDatabase(dbPath, countryCode);
await this.init();
this.dbPath = dbPath;
return countryCode;
2022-03-22 09:28:36 +00:00
}
2022-03-31 09:04:30 +00:00
async init() {
this.schemaMap = (await this.#demux.getSchemaMap()) as Readonly<SchemaMap>;
2022-04-18 05:07:36 +00:00
for (const schemaName in this.schemaMap) {
const fields = this.schemaMap[schemaName]!.fields!;
this.fieldValueMap[schemaName] = getMapFromList(fields, 'fieldname');
}
2022-03-31 09:04:30 +00:00
}
async insert(
schemaName: string,
docValueMap: DocValueMap
): Promise<DocValueMap> {
2022-04-18 05:07:36 +00:00
let rawValueMap = this.converter.toRawValueMap(
2022-03-31 09:04:30 +00:00
schemaName,
docValueMap
) as RawValueMap;
rawValueMap = (await this.#demux.call(
'insert',
schemaName,
rawValueMap
)) as RawValueMap;
2022-04-18 05:07:36 +00:00
return this.converter.toDocValueMap(schemaName, rawValueMap) as DocValueMap;
2022-03-31 09:04:30 +00:00
}
// Read
async get(
schemaName: string,
name: string,
fields?: string | string[]
): Promise<DocValueMap> {
const rawValueMap = (await this.#demux.call(
'get',
schemaName,
name,
fields
)) as RawValueMap;
2022-04-18 05:07:36 +00:00
return this.converter.toDocValueMap(schemaName, rawValueMap) as DocValueMap;
2022-03-31 09:04:30 +00:00
}
async getAll(
schemaName: string,
options: GetAllOptions = {}
2022-03-31 09:04:30 +00:00
): Promise<DocValueMap[]> {
const rawValueMap = await this.#getAll(schemaName, options);
2022-04-18 05:07:36 +00:00
return this.converter.toDocValueMap(
schemaName,
rawValueMap
) as DocValueMap[];
}
async getAllRaw(
schemaName: string,
options: GetAllOptions = {}
): Promise<DocValueMap[]> {
return await this.#getAll(schemaName, options);
}
2022-03-31 09:04:30 +00:00
async getSingleValues(
...fieldnames: ({ fieldname: string; parent?: string } | string)[]
2022-03-31 11:43:20 +00:00
): Promise<SingleValue<DocValue>> {
const rawSingleValue = (await this.#demux.call(
'getSingleValues',
...fieldnames
)) as SingleValue<RawValue>;
2022-04-18 05:07:36 +00:00
const docSingleValue: SingleValue<DocValue> = [];
for (const sv of rawSingleValue) {
const fieldtype = this.fieldValueMap[sv.parent][sv.fieldname].fieldtype;
const value = Converter.toDocValue(sv.value, fieldtype, this.#fyo);
2022-04-18 05:07:36 +00:00
docSingleValue.push({
value,
parent: sv.parent,
fieldname: sv.fieldname,
});
}
return docSingleValue;
}
async count(
schemaName: string,
options: GetAllOptions = {}
): Promise<number> {
const rawValueMap = await this.#getAll(schemaName, options);
return rawValueMap.length;
2022-03-31 09:04:30 +00:00
}
// Update
async rename(
schemaName: string,
oldName: string,
newName: string
): Promise<void> {
await this.#demux.call('rename', schemaName, oldName, newName);
}
async update(schemaName: string, docValueMap: DocValueMap): Promise<void> {
2022-04-18 05:07:36 +00:00
const rawValueMap = this.converter.toRawValueMap(schemaName, docValueMap);
2022-03-31 09:04:30 +00:00
await this.#demux.call('update', schemaName, rawValueMap);
}
// Delete
async delete(schemaName: string, name: string): Promise<void> {
await this.#demux.call('delete', schemaName, name);
}
// Other
async close(): Promise<void> {
await this.#demux.call('close');
}
async exists(schemaName: string, name?: string): Promise<boolean> {
return (await this.#demux.call('exists', schemaName, name)) as boolean;
}
/**
* Bespoke function
*
* These are functions to run custom queries that are too complex for
2022-04-18 05:07:36 +00:00
* DatabaseCore and require use of knex or raw queries. The output
* of these is not converted to DocValue and is used as is (RawValue).
*
* The query logic for these is in backend/database/bespoke.ts
*/
async getTopExpenses(fromDate: string, toDate: string): Promise<TopExpenses> {
return (await this.#demux.callBespoke(
'getTopExpenses',
fromDate,
toDate
)) as TopExpenses;
}
async getTotalOutstanding(
schemaName: string,
fromDate: string,
toDate: string
): Promise<TotalOutstanding> {
return (await this.#demux.callBespoke(
'getTotalOutstanding',
schemaName,
fromDate,
toDate
)) as TotalOutstanding;
}
async getCashflow(fromDate: string, toDate: string): Promise<Cashflow> {
return (await this.#demux.callBespoke(
'getCashflow',
fromDate,
toDate
)) as Cashflow;
}
2022-04-18 05:07:36 +00:00
/**
* Internal methods
*/
async #getAll(
2022-03-31 09:04:30 +00:00
schemaName: string,
2022-04-18 05:07:36 +00:00
options: GetAllOptions = {}
): Promise<RawValueMap[]> {
return (await this.#demux.call(
'getAll',
schemaName,
options
)) as RawValueMap[];
2022-03-31 11:43:20 +00:00
}
2022-03-22 09:28:36 +00:00
}