2022-04-01 09:35:51 +00:00
|
|
|
import Doc from 'frappe/model/doc';
|
2022-04-07 06:20:14 +00:00
|
|
|
import { DocMap, ModelMap } from 'frappe/model/types';
|
|
|
|
import { getRandomString } from 'frappe/utils';
|
2022-03-22 09:28:36 +00:00
|
|
|
import Observable from 'frappe/utils/observable';
|
2022-04-01 09:35:51 +00:00
|
|
|
import { Frappe } from '..';
|
2022-04-07 06:20:14 +00:00
|
|
|
import { DocValue, DocValueMap } from './types';
|
2022-03-22 09:28:36 +00:00
|
|
|
|
|
|
|
export class DocHandler {
|
|
|
|
frappe: Frappe;
|
|
|
|
singles: DocMap = {};
|
2022-04-07 06:20:14 +00:00
|
|
|
docs: Observable<DocMap> = new Observable();
|
|
|
|
models: ModelMap = {};
|
2022-03-22 09:28:36 +00:00
|
|
|
|
|
|
|
constructor(frappe: Frappe) {
|
|
|
|
this.frappe = frappe;
|
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
this.models = {};
|
|
|
|
this.docs = new Observable();
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
registerModels(models: ModelMap) {
|
|
|
|
for (const schemaName in models) {
|
|
|
|
this.models[schemaName] = models[schemaName];
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cache operations
|
|
|
|
*/
|
|
|
|
|
|
|
|
addToCache(doc: Doc) {
|
2022-04-07 06:20:14 +00:00
|
|
|
if (!this.docs) {
|
|
|
|
return;
|
|
|
|
}
|
2022-03-22 09:28:36 +00:00
|
|
|
|
|
|
|
// add to `docs` cache
|
2022-04-07 06:20:14 +00:00
|
|
|
const name = doc.name;
|
|
|
|
const schemaName = doc.schemaName;
|
2022-03-22 09:28:36 +00:00
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
if (!name) {
|
2022-03-22 09:28:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
if (!this.docs[schemaName]) {
|
|
|
|
this.docs[schemaName] = {};
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
(this.docs[schemaName] as DocMap)[name] = doc;
|
2022-03-22 09:28:36 +00:00
|
|
|
|
|
|
|
// singles available as first level objects too
|
2022-04-07 06:20:14 +00:00
|
|
|
if (schemaName === doc.name) {
|
2022-03-22 09:28:36 +00:00
|
|
|
this.singles[name] = doc;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
// propagate change to `docs`
|
2022-03-22 09:28:36 +00:00
|
|
|
doc.on('change', (params: unknown) => {
|
|
|
|
this.docs!.trigger('change', params);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
removeFromCache(schemaName: string, name: string) {
|
|
|
|
const docMap = this.docs[schemaName] as DocMap | undefined;
|
|
|
|
delete docMap?.[name];
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
getFromCache(schemaName: string, name: string): Doc | undefined {
|
|
|
|
const docMap = this.docs[schemaName] as DocMap | undefined;
|
|
|
|
return docMap?.[name];
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
getCachedValue(
|
|
|
|
schemaName: string,
|
|
|
|
name: string,
|
|
|
|
fieldname: string
|
|
|
|
): DocValue | Doc[] | undefined {
|
|
|
|
const docMap = this.docs[schemaName] as DocMap;
|
|
|
|
const doc = docMap[name];
|
2022-03-22 09:28:36 +00:00
|
|
|
if (doc === undefined) {
|
2022-04-07 06:20:14 +00:00
|
|
|
return;
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
return doc.get(fieldname);
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
isDirty(schemaName: string, name: string): boolean {
|
|
|
|
const doc = (this.docs?.[schemaName] as DocMap)?.[name];
|
|
|
|
if (doc === undefined) {
|
|
|
|
return false;
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
return doc.dirty;
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Doc Operations
|
|
|
|
*/
|
|
|
|
|
|
|
|
async getDoc(
|
2022-04-07 06:20:14 +00:00
|
|
|
schemaName: string,
|
2022-03-22 09:28:36 +00:00
|
|
|
name: string,
|
|
|
|
options = { skipDocumentCache: false }
|
|
|
|
) {
|
2022-04-07 06:20:14 +00:00
|
|
|
let doc: Doc | undefined;
|
2022-03-22 09:28:36 +00:00
|
|
|
if (!options?.skipDocumentCache) {
|
2022-04-07 06:20:14 +00:00
|
|
|
doc = this.getFromCache(schemaName, name);
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (doc) {
|
|
|
|
return doc;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
doc = this.getNewDoc(schemaName, { name });
|
2022-03-22 09:28:36 +00:00
|
|
|
await doc.load();
|
|
|
|
this.addToCache(doc);
|
|
|
|
|
|
|
|
return doc;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
getModel(schemaName: string): typeof Doc {
|
|
|
|
const Model = this.models[schemaName];
|
|
|
|
if (Model === undefined) {
|
|
|
|
return Doc;
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
return Model;
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
async getSingle(schemaName: string) {
|
|
|
|
return await this.getDoc(schemaName, schemaName);
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
async getDuplicate(doc: Doc): Promise<Doc> {
|
|
|
|
const newDoc = await doc.duplicate(false);
|
|
|
|
delete newDoc.name;
|
2022-03-22 09:28:36 +00:00
|
|
|
return newDoc;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
getEmptyDoc(schemaName: string, cacheDoc: boolean = true): Doc {
|
|
|
|
const doc = this.getNewDoc(schemaName);
|
2022-03-22 09:28:36 +00:00
|
|
|
doc.name = getRandomString();
|
|
|
|
|
|
|
|
if (cacheDoc) {
|
|
|
|
this.addToCache(doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return doc;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
getNewDoc(schemaName: string, data: DocValueMap = {}): Doc {
|
|
|
|
const Model = this.getModel(schemaName);
|
|
|
|
const schema = this.frappe.schemaMap[schemaName];
|
|
|
|
if (schema === undefined) {
|
|
|
|
throw new Error(`Schema not found for ${schemaName}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const doc = new Model(schema, data);
|
2022-03-22 09:28:36 +00:00
|
|
|
doc.setDefaults();
|
|
|
|
return doc;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
async syncDoc(schemaName: string, data: DocValueMap) {
|
|
|
|
const name = data.name as string | undefined;
|
|
|
|
if (name === undefined) {
|
2022-03-22 09:28:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
const docExists = await this.frappe.db.exists(schemaName, name);
|
|
|
|
if (!docExists) {
|
|
|
|
const doc = this.getNewDoc(schemaName, data);
|
|
|
|
await doc.insert;
|
|
|
|
return;
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|
2022-04-01 09:35:51 +00:00
|
|
|
|
2022-04-07 06:20:14 +00:00
|
|
|
const doc = await this.getDoc(schemaName, name);
|
|
|
|
await doc.setMultiple(data);
|
|
|
|
await doc.update();
|
|
|
|
}
|
2022-03-22 09:28:36 +00:00
|
|
|
}
|