2
0
mirror of https://github.com/frappe/books.git synced 2024-12-23 03:19:01 +00:00

chore: fix types

This commit is contained in:
18alantom 2022-03-25 15:42:39 +05:30
parent 7514c95883
commit 74bfe7931c
9 changed files with 149 additions and 119 deletions

View File

@ -1,21 +1,23 @@
export const sqliteTypeMap = { import { KnexColumnType } from './database/types';
export const sqliteTypeMap: Record<string, KnexColumnType> = {
AutoComplete: 'text', AutoComplete: 'text',
Currency: 'text', Currency: 'text',
Int: 'integer', Int: 'integer',
Float: 'float', Float: 'float',
Percent: 'float', Percent: 'float',
Check: 'integer', Check: 'boolean',
Code: 'text', Code: 'text',
Date: 'text', Date: 'date',
Datetime: 'text', Datetime: 'datetime',
Time: 'text', Time: 'time',
Text: 'text', Text: 'text',
Data: 'text', Data: 'text',
Link: 'text', Link: 'text',
DynamicLink: 'text', DynamicLink: 'text',
Password: 'text', Password: 'text',
Select: 'text', Select: 'text',
File: 'text', File: 'binary',
Attach: 'text', Attach: 'text',
AttachImage: 'text', AttachImage: 'text',
Color: 'text', Color: 'text',

View File

@ -6,14 +6,14 @@ import {
DuplicateEntryError, DuplicateEntryError,
LinkValidationError, LinkValidationError,
NotFoundError, NotFoundError,
ValueError, ValueError
} from '../../frappe/utils/errors'; } from '../../frappe/utils/errors';
import { import {
Field, Field,
FieldTypeEnum, FieldTypeEnum,
RawValue, RawValue,
SchemaMap, SchemaMap,
TargetField, TargetField
} from '../../schemas/types'; } from '../../schemas/types';
import { sqliteTypeMap } from '../common'; import { sqliteTypeMap } from '../common';
import { import {
@ -21,11 +21,11 @@ import {
FieldValueMap, FieldValueMap,
GetAllOptions, GetAllOptions,
GetQueryBuilderOptions, GetQueryBuilderOptions,
QueryFilter, QueryFilter
} from './types'; } from './types';
export default class DatabaseCore { export default class DatabaseCore {
knex: Knex; knex?: Knex;
typeMap = sqliteTypeMap; typeMap = sqliteTypeMap;
dbPath: string; dbPath: string;
schemaMap: SchemaMap = {}; schemaMap: SchemaMap = {};
@ -39,7 +39,7 @@ export default class DatabaseCore {
filename: this.dbPath, filename: this.dbPath,
}, },
pool: { pool: {
afterCreate(conn, done) { afterCreate(conn: { run: (query: string) => void }, done: () => void) {
conn.run('PRAGMA foreign_keys=ON'); conn.run('PRAGMA foreign_keys=ON');
done(); done();
}, },
@ -61,21 +61,22 @@ export default class DatabaseCore {
} }
close() { close() {
this.knex.destroy(); this.knex!.destroy();
} }
async commit() { async commit() {
try { try {
await this.raw('commit'); await this.raw('commit');
} catch (err) { } catch (err) {
if (err.type !== CannotCommitError) { const type = this.#getError(err as Error);
if (type !== CannotCommitError) {
throw err; throw err;
} }
} }
} }
async raw(query: string, params: Knex.RawBinding[] = []) { async raw(query: string, params: Knex.RawBinding[] = []) {
return await this.knex.raw(query, params); return await this.knex!.raw(query, params);
} }
async migrate() { async migrate() {
@ -104,7 +105,7 @@ export default class DatabaseCore {
let row = []; let row = [];
try { try {
const qb = this.knex(schemaName); const qb = this.knex!(schemaName);
if (name !== undefined) { if (name !== undefined) {
qb.where({ name }); qb.where({ name });
} }
@ -197,7 +198,7 @@ export default class DatabaseCore {
groupBy, groupBy,
orderBy = 'creation', orderBy = 'creation',
order = 'desc', order = 'desc',
}: GetAllOptions = {}): Promise<FieldValueMap[]> { }: GetAllOptions): Promise<FieldValueMap[]> {
const schema = this.schemaMap[schemaName]; const schema = this.schemaMap[schemaName];
if (!fields) { if (!fields) {
fields = ['name', ...(schema.keywordFields ?? [])]; fields = ['name', ...(schema.keywordFields ?? [])];
@ -207,7 +208,7 @@ export default class DatabaseCore {
fields = [fields]; fields = [fields];
} }
return (await this.#getQueryBuilder(schemaName, fields, filters, { return (await this.#getQueryBuilder(schemaName, fields, filters ?? {}, {
offset: start, offset: start,
limit, limit,
groupBy, groupBy,
@ -226,7 +227,7 @@ export default class DatabaseCore {
return fieldname; return fieldname;
}); });
let builder = this.knex('SingleValue'); let builder = this.knex!('SingleValue');
builder = builder.where(fieldnames[0]); builder = builder.where(fieldnames[0]);
fieldnames.slice(1).forEach(({ fieldname, parent }) => { fieldnames.slice(1).forEach(({ fieldname, parent }) => {
@ -252,7 +253,7 @@ export default class DatabaseCore {
} }
async rename(schemaName: string, oldName: string, newName: string) { async rename(schemaName: string, oldName: string, newName: string) {
await this.knex(schemaName) await this.knex!(schemaName)
.update({ name: newName }) .update({ name: newName })
.where('name', oldName); .where('name', oldName);
await this.commit(); await this.commit();
@ -282,15 +283,15 @@ export default class DatabaseCore {
} }
async #tableExists(schemaName: string) { async #tableExists(schemaName: string) {
return await this.knex.schema.hasTable(schemaName); return await this.knex!.schema.hasTable(schemaName);
} }
async #singleExists(singleSchemaName: string) { async #singleExists(singleSchemaName: string) {
const res = await this.knex('SingleValue') const res = await this.knex!('SingleValue')
.count('parent as count') .count('parent as count')
.where('parent', singleSchemaName) .where('parent', singleSchemaName)
.first(); .first();
return res.count > 0; return (res?.count ?? 0) > 0;
} }
async #removeColumns(schemaName: string, targetColumns: string[]) { async #removeColumns(schemaName: string, targetColumns: string[]) {
@ -298,7 +299,7 @@ export default class DatabaseCore {
} }
async #deleteSingleValues(singleSchemaName: string) { async #deleteSingleValues(singleSchemaName: string) {
return await this.knex('SingleValue') return await this.knex!('SingleValue')
.where('parent', singleSchemaName) .where('parent', singleSchemaName)
.delete(); .delete();
} }
@ -325,9 +326,9 @@ export default class DatabaseCore {
// Alter table hacx for sqlite in case of schema change. // Alter table hacx for sqlite in case of schema change.
const tempName = `__${schemaName}`; const tempName = `__${schemaName}`;
await this.knex.schema.dropTableIfExists(tempName); await this.knex!.schema.dropTableIfExists(tempName);
await this.knex.raw('PRAGMA foreign_keys=OFF'); await this.knex!.raw('PRAGMA foreign_keys=OFF');
await this.#createTable(schemaName, tempName); await this.#createTable(schemaName, tempName);
if (tableRows.length > 200) { if (tableRows.length > 200) {
@ -337,27 +338,29 @@ export default class DatabaseCore {
if (rowSlice.length === 0) { if (rowSlice.length === 0) {
break; break;
} }
await this.knex.batchInsert(tempName, rowSlice); await this.knex!.batchInsert(tempName, rowSlice);
} }
} else { } else {
await this.knex.batchInsert(tempName, tableRows); await this.knex!.batchInsert(tempName, tableRows);
} }
await this.knex.schema.dropTable(schemaName); await this.knex!.schema.dropTable(schemaName);
await this.knex.schema.renameTable(tempName, schemaName); await this.knex!.schema.renameTable(tempName, schemaName);
await this.knex.raw('PRAGMA foreign_keys=ON'); await this.knex!.raw('PRAGMA foreign_keys=ON');
} }
async #getTableColumns(schemaName: string): Promise<string[]> { async #getTableColumns(schemaName: string): Promise<string[]> {
const info = await this.raw(`PRAGMA table_info(${schemaName})`); const info: FieldValueMap[] = await this.raw(
return info.map((d) => d.name); `PRAGMA table_info(${schemaName})`
);
return info.map((d) => d.name as string);
} }
async #getForeignKeys(schemaName: string): Promise<string[]> { async #getForeignKeys(schemaName: string): Promise<string[]> {
const foreignKeyList = await this.raw( const foreignKeyList: FieldValueMap[] = await this.raw(
`PRAGMA foreign_key_list(${schemaName})` `PRAGMA foreign_key_list(${schemaName})`
); );
return foreignKeyList.map((d) => d.from); return foreignKeyList.map((d) => d.from as string);
} }
#getQueryBuilder( #getQueryBuilder(
@ -366,7 +369,7 @@ export default class DatabaseCore {
filters: QueryFilter, filters: QueryFilter,
options: GetQueryBuilderOptions options: GetQueryBuilderOptions
): Knex.QueryBuilder { ): Knex.QueryBuilder {
const builder = this.knex.select(fields).from(schemaName); const builder = this.knex!.select(fields).from(schemaName);
this.#applyFiltersToBuilder(builder, filters); this.#applyFiltersToBuilder(builder, filters);
@ -432,9 +435,9 @@ export default class DatabaseCore {
filtersArray.map((filter) => { filtersArray.map((filter) => {
const [field, operator, comparisonValue] = filter; const [field, operator, comparisonValue] = filter;
if (operator === '=') { if (operator === '=') {
builder.where(field, comparisonValue); builder.where(field as string, comparisonValue);
} else { } else {
builder.where(field, operator, comparisonValue); builder.where(field as string, operator as string, comparisonValue);
} }
}); });
} }
@ -445,10 +448,8 @@ export default class DatabaseCore {
const diff: ColumnDiff = { added: [], removed: [] }; const diff: ColumnDiff = { added: [], removed: [] };
for (const field of validFields) { for (const field of validFields) {
if ( const hasDbType = this.typeMap.hasOwnProperty(field.fieldtype);
!tableColumns.includes(field.fieldname) && if (!tableColumns.includes(field.fieldname) && hasDbType) {
this.typeMap[field.fieldtype]
) {
diff.added.push(field); diff.added.push(field);
} }
} }
@ -463,7 +464,7 @@ export default class DatabaseCore {
return diff; return diff;
} }
async #getNewForeignKeys(schemaName): Promise<Field[]> { async #getNewForeignKeys(schemaName: string): Promise<Field[]> {
const foreignKeys = await this.#getForeignKeys(schemaName); const foreignKeys = await this.#getForeignKeys(schemaName);
const newForeignKeys: Field[] = []; const newForeignKeys: Field[] = [];
const schema = this.schemaMap[schemaName]; const schema = this.schemaMap[schemaName];
@ -490,7 +491,9 @@ export default class DatabaseCore {
return; return;
} }
const column = table[columnType](field.fieldname); const column = table[columnType](
field.fieldname
) as Knex.SqlLiteColumnBuilder;
// primary key // primary key
if (field.fieldname === 'name') { if (field.fieldname === 'name') {
@ -525,8 +528,7 @@ export default class DatabaseCore {
const diff: ColumnDiff = await this.#getColumnDiff(schemaName); const diff: ColumnDiff = await this.#getColumnDiff(schemaName);
const newForeignKeys: Field[] = await this.#getNewForeignKeys(schemaName); const newForeignKeys: Field[] = await this.#getNewForeignKeys(schemaName);
return this.knex.schema return this.knex!.schema.table(schemaName, (table) => {
.table(schemaName, (table) => {
if (diff.added.length) { if (diff.added.length) {
for (const field of diff.added) { for (const field of diff.added) {
this.#buildColumnForTable(table, field); this.#buildColumnForTable(table, field);
@ -536,8 +538,7 @@ export default class DatabaseCore {
if (diff.removed.length) { if (diff.removed.length) {
this.#removeColumns(schemaName, diff.removed); this.#removeColumns(schemaName, diff.removed);
} }
}) }).then(() => {
.then(() => {
if (newForeignKeys.length) { if (newForeignKeys.length) {
return this.#addForeignKeys(schemaName, newForeignKeys); return this.#addForeignKeys(schemaName, newForeignKeys);
} }
@ -551,7 +552,7 @@ export default class DatabaseCore {
} }
#runCreateTableQuery(schemaName: string, fields: Field[]) { #runCreateTableQuery(schemaName: string, fields: Field[]) {
return this.knex.schema.createTable(schemaName, (table) => { return this.knex!.schema.createTable(schemaName, (table) => {
for (const field of fields) { for (const field of fields) {
this.#buildColumnForTable(table, field); this.#buildColumnForTable(table, field);
} }
@ -560,7 +561,7 @@ export default class DatabaseCore {
async #getNonExtantSingleValues(singleSchemaName: string) { async #getNonExtantSingleValues(singleSchemaName: string) {
const existingFields = ( const existingFields = (
await this.knex('SingleValue') await this.knex!('SingleValue')
.where({ parent: singleSchemaName }) .where({ parent: singleSchemaName })
.select('fieldname') .select('fieldname')
).map(({ fieldname }) => fieldname); ).map(({ fieldname }) => fieldname);
@ -577,11 +578,11 @@ export default class DatabaseCore {
} }
async #deleteOne(schemaName: string, name: string) { async #deleteOne(schemaName: string, name: string) {
return this.knex(schemaName).where('name', name).delete(); return this.knex!(schemaName).where('name', name).delete();
} }
#deleteChildren(schemaName: string, parentName: string) { #deleteChildren(schemaName: string, parentName: string) {
return this.knex(schemaName).where('parent', parentName).delete(); return this.knex!(schemaName).where('parent', parentName).delete();
} }
#runDeleteOtherChildren( #runDeleteOtherChildren(
@ -590,7 +591,7 @@ export default class DatabaseCore {
added: string[] added: string[]
) { ) {
// delete other children // delete other children
return this.knex(field.target) return this.knex!(field.target)
.where('parent', parentName) .where('parent', parentName)
.andWhere('name', 'not in', added) .andWhere('name', 'not in', added)
.delete(); .delete();
@ -623,21 +624,21 @@ export default class DatabaseCore {
try { try {
// copy from old to new table // copy from old to new table
await this.knex(tempName).insert(this.knex.select().from(schemaName)); await this.knex!(tempName).insert(this.knex!.select().from(schemaName));
} catch (err) { } catch (err) {
await this.raw('ROLLBACK'); await this.raw('ROLLBACK');
await this.raw('PRAGMA foreign_keys=ON'); await this.raw('PRAGMA foreign_keys=ON');
const rows = await this.knex.select().from(schemaName); const rows = await this.knex!.select().from(schemaName);
await this.prestigeTheTable(schemaName, rows); await this.prestigeTheTable(schemaName, rows);
return; return;
} }
// drop old table // drop old table
await this.knex.schema.dropTable(schemaName); await this.knex!.schema.dropTable(schemaName);
// rename new table // rename new table
await this.knex.schema.renameTable(tempName, schemaName); await this.knex!.schema.renameTable(tempName, schemaName);
await this.raw('COMMIT'); await this.raw('COMMIT');
await this.raw('PRAGMA foreign_keys=ON'); await this.raw('PRAGMA foreign_keys=ON');
@ -663,8 +664,7 @@ export default class DatabaseCore {
name: string, name: string,
fields: string | string[] = '*' fields: string | string[] = '*'
) { ) {
const fieldValueMap: FieldValueMap = await this.knex const fieldValueMap: FieldValueMap = await this.knex!.select(fields)
.select(fields)
.from(schemaName) .from(schemaName)
.where('name', name) .where('name', name)
.first(); .first();
@ -694,7 +694,7 @@ export default class DatabaseCore {
fieldValueMap.name = getRandomString(); fieldValueMap.name = getRandomString();
} }
const validMap = {}; const validMap: FieldValueMap = {};
for (const { fieldname, fieldtype } of fields) { for (const { fieldname, fieldtype } of fields) {
if (fieldtype === FieldTypeEnum.Table) { if (fieldtype === FieldTypeEnum.Table) {
continue; continue;
@ -703,7 +703,7 @@ export default class DatabaseCore {
validMap[fieldname] = fieldValueMap[fieldname]; validMap[fieldname] = fieldValueMap[fieldname];
} }
return this.knex(schemaName).insert(fieldValueMap); return this.knex!(schemaName).insert(fieldValueMap);
} }
async #updateSingleValues( async #updateSingleValues(
@ -728,7 +728,7 @@ export default class DatabaseCore {
fieldname: string, fieldname: string,
value: RawValue value: RawValue
) { ) {
return await this.knex('SingleValue') return await this.knex!('SingleValue')
.where({ .where({
parent: singleSchemaName, parent: singleSchemaName,
fieldname, fieldname,
@ -758,7 +758,7 @@ export default class DatabaseCore {
} }
return acc; return acc;
}, {}); }, {} as FieldValueMap);
await this.#updateSingleValues(schemaName, defaultValues); await this.#updateSingleValues(schemaName, defaultValues);
} }
@ -767,7 +767,7 @@ export default class DatabaseCore {
async #updateNonExtantSingleValues(schemaName: string) { async #updateNonExtantSingleValues(schemaName: string) {
const singleValues = await this.#getNonExtantSingleValues(schemaName); const singleValues = await this.#getNonExtantSingleValues(schemaName);
for (const sv of singleValues) { for (const sv of singleValues) {
await this.#updateSingleValue(schemaName, sv.fieldname, sv.value); await this.#updateSingleValue(schemaName, sv.fieldname, sv.value!);
} }
} }
@ -775,7 +775,7 @@ export default class DatabaseCore {
const updateMap = { ...fieldValueMap }; const updateMap = { ...fieldValueMap };
delete updateMap.name; delete updateMap.name;
return await this.knex(schemaName) return await this.knex!(schemaName)
.where('name', fieldValueMap.name as string) .where('name', fieldValueMap.name as string)
.update(updateMap); .update(updateMap);
} }

View File

@ -6,7 +6,7 @@ import { runPatches } from './runPatch';
import { Patch } from './types'; import { Patch } from './types';
export class DatabaseManager { export class DatabaseManager {
db: DatabaseCore; db?: DatabaseCore;
constructor() {} constructor() {}
async createNewDatabase(dbPath: string, countryCode: string) { async createNewDatabase(dbPath: string, countryCode: string) {
@ -26,6 +26,10 @@ export class DatabaseManager {
} }
async migrate() { async migrate() {
if (this.db === undefined) {
return;
}
const patchesToExecute = await this.#getPatchesToExecute(); const patchesToExecute = await this.#getPatchesToExecute();
const preMigrationPatches = patchesToExecute.filter( const preMigrationPatches = patchesToExecute.filter(
(p) => p.patch.beforeMigrate (p) => p.patch.beforeMigrate
@ -40,21 +44,26 @@ export class DatabaseManager {
} }
async #getPatchesToExecute(): Promise<Patch[]> { async #getPatchesToExecute(): Promise<Patch[]> {
const query: { name: string }[] = await this.db if (this.db === undefined) {
.knex('PatchRun') return [];
.select('name'); }
const query: { name: string }[] = await this.db.knex!('PatchRun').select(
'name'
);
const executedPatches = query.map((q) => q.name); const executedPatches = query.map((q) => q.name);
return patches.filter((p) => !executedPatches.includes(p.name)); return patches.filter((p) => !executedPatches.includes(p.name));
} }
async #getCountryCode(): Promise<string | undefined> { async #getCountryCode(): Promise<string | undefined> {
if (!this.db) { if (this.db === undefined) {
return undefined; return undefined;
} }
const query = await this.db const query = await this.db.knex!('SingleValue').where({
.knex('SingleValue') fieldname: 'countryCode',
.where({ fieldname: 'countryCode', parent: 'SystemSettings' }); parent: 'SystemSettings',
});
if (query.length > 0) { if (query.length > 0) {
return query[0].countryCode as string; return query[0].countryCode as string;
@ -67,7 +76,7 @@ export class DatabaseManager {
try { try {
fs.unlink(dbPath); fs.unlink(dbPath);
} catch (err) { } catch (err) {
if (err.code === 'ENOENT') { if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
return; return;
} }

View File

@ -27,5 +27,5 @@ async function runPatch(patch: Patch, dm: DatabaseManager): Promise<boolean> {
async function makeEntry(patchName: string, dm: DatabaseManager) { async function makeEntry(patchName: string, dm: DatabaseManager) {
const defaultFieldValueMap = getDefaultMetaFieldValueMap() as FieldValueMap; const defaultFieldValueMap = getDefaultMetaFieldValueMap() as FieldValueMap;
defaultFieldValueMap.name = patchName; defaultFieldValueMap.name = patchName;
await dm.db.insert('PatchRun', defaultFieldValueMap); await dm.db!.insert('PatchRun', defaultFieldValueMap);
} }

View File

@ -1,19 +1,20 @@
import { Field, RawValue } from '../../schemas/types'; import { Field, RawValue } from '../../schemas/types';
import { DatabaseManager } from './manager';
export type QueryFilter = Record<string, string | string[]>; export type QueryFilter = Record<string, string | string[]>;
export interface GetQueryBuilderOptions { export interface GetQueryBuilderOptions {
offset: number; offset?: number;
limit: number; limit?: number;
groupBy: string; groupBy?: string;
orderBy: string; orderBy?: string;
order: 'desc' | 'asc'; order?: 'desc' | 'asc';
} }
export interface GetAllOptions { export interface GetAllOptions {
schemaName?: string; schemaName: string;
fields?: string[]; fields?: string[];
filters?: Record<string, string>; filters?: QueryFilter;
start?: number; start?: number;
limit?: number; limit?: number;
groupBy?: string; groupBy?: string;
@ -31,7 +32,17 @@ export interface Patch {
name: string; name: string;
version: string; version: string;
patch: { patch: {
execute: (DatabaseManager) => Promise<void>; execute: (dm: DatabaseManager) => Promise<void>;
beforeMigrate?: boolean; beforeMigrate?: boolean;
}; };
} }
export type KnexColumnType =
| 'text'
| 'integer'
| 'float'
| 'boolean'
| 'date'
| 'datetime'
| 'time'
| 'binary';

View File

@ -1,15 +1,15 @@
export function getMapFromList<T>( export function getMapFromList<T, K extends keyof T>(
list: T[], list: T[],
name: string = 'name' name: K
): Record<string, T> { ): Record<string, T> {
const acc: Record<string, T> = {}; const acc: Record<string, T> = {};
for (const t of list) { for (const t of list) {
const key = t[name] as string | undefined; const key = t[name];
if (key === undefined) { if (key === undefined) {
continue; continue;
} }
acc[key] = t; acc[String(key)] = t;
} }
return acc; return acc;
} }

View File

@ -13,8 +13,8 @@ export function getSchemas(countryCode: string = '-'): SchemaMap {
return schemaMap; return schemaMap;
} }
function addMetaFields(schemaMap: SchemaMap): SchemaMap { export function addMetaFields(schemaMap: SchemaMap): SchemaMap {
const metaSchemaMap = getMapFromList(metaSchemas); const metaSchemaMap = getMapFromList(metaSchemas, 'name');
const base = metaSchemaMap.base; const base = metaSchemaMap.base;
const tree = getCombined(metaSchemaMap.tree, base); const tree = getCombined(metaSchemaMap.tree, base);
@ -29,15 +29,15 @@ function addMetaFields(schemaMap: SchemaMap): SchemaMap {
} }
if (schema.isTree && schema.isSubmittable) { if (schema.isTree && schema.isSubmittable) {
schema.fields = [...schema.fields, ...submittableTree.fields]; schema.fields = [...schema.fields, ...submittableTree.fields!];
} else if (schema.isTree) { } else if (schema.isTree) {
schema.fields = [...schema.fields, ...tree.fields]; schema.fields = [...schema.fields, ...tree.fields!];
} else if (schema.isSubmittable) { } else if (schema.isSubmittable) {
schema.fields = [...schema.fields, ...submittable.fields]; schema.fields = [...schema.fields, ...submittable.fields!];
} else if (schema.isChild) { } else if (schema.isChild) {
schema.fields = [...schema.fields, ...child.fields]; schema.fields = [...schema.fields, ...child.fields!];
} else { } else {
schema.fields = [...schema.fields, ...base.fields]; schema.fields = [...schema.fields, ...base.fields!];
} }
} }
@ -45,18 +45,23 @@ function addMetaFields(schemaMap: SchemaMap): SchemaMap {
} }
function getCoreSchemas(): SchemaMap { function getCoreSchemas(): SchemaMap {
const rawSchemaMap = getMapFromList(coreSchemas); const rawSchemaMap = getMapFromList(coreSchemas, 'name');
const coreSchemaMap = getAbstractCombinedSchemas(rawSchemaMap); const coreSchemaMap = getAbstractCombinedSchemas(rawSchemaMap);
return cleanSchemas(coreSchemaMap); return cleanSchemas(coreSchemaMap);
} }
function getAppSchemas(countryCode: string): SchemaMap { function getAppSchemas(countryCode: string): SchemaMap {
const combinedSchemas = getRegionalCombinedSchemas(countryCode); const appSchemaMap = getMapFromList(appSchemas, 'name');
const regionalSchemaMap = getRegionalSchemaMap(countryCode);
const combinedSchemas = getRegionalCombinedSchemas(
appSchemaMap,
regionalSchemaMap
);
const schemaMap = getAbstractCombinedSchemas(combinedSchemas); const schemaMap = getAbstractCombinedSchemas(combinedSchemas);
return cleanSchemas(schemaMap); return cleanSchemas(schemaMap);
} }
function cleanSchemas(schemaMap: SchemaMap): SchemaMap { export function cleanSchemas(schemaMap: SchemaMap): SchemaMap {
for (const name in schemaMap) { for (const name in schemaMap) {
const schema = schemaMap[name]; const schema = schemaMap[name];
if (schema.isAbstract && !schema.extends) { if (schema.isAbstract && !schema.extends) {
@ -97,13 +102,13 @@ function getCombined(
return combined; return combined;
} }
function getAbstractCombinedSchemas(schemas: SchemaStubMap): SchemaMap { export function getAbstractCombinedSchemas(schemas: SchemaStubMap): SchemaMap {
const abstractSchemaNames: string[] = Object.keys(schemas).filter( const abstractSchemaNames: string[] = Object.keys(schemas).filter(
(n) => schemas[n].isAbstract (n) => schemas[n].isAbstract
); );
const extendingSchemaNames: string[] = Object.keys(schemas).filter((n) => const extendingSchemaNames: string[] = Object.keys(schemas).filter((n) =>
abstractSchemaNames.includes(schemas[n].extends) abstractSchemaNames.includes(schemas[n].extends ?? '')
); );
const completeSchemas: Schema[] = Object.keys(schemas) const completeSchemas: Schema[] = Object.keys(schemas)
@ -113,11 +118,11 @@ function getAbstractCombinedSchemas(schemas: SchemaStubMap): SchemaMap {
) )
.map((n) => schemas[n] as Schema); .map((n) => schemas[n] as Schema);
const schemaMap = getMapFromList(completeSchemas) as SchemaMap; const schemaMap = getMapFromList(completeSchemas, 'name') as SchemaMap;
for (const name of extendingSchemaNames) { for (const name of extendingSchemaNames) {
const extendingSchema = schemas[name] as Schema; const extendingSchema = schemas[name] as Schema;
const abstractSchema = schemas[extendingSchema.extends] as SchemaStub; const abstractSchema = schemas[extendingSchema.extends!] as SchemaStub;
schemaMap[name] = getCombined(extendingSchema, abstractSchema) as Schema; schemaMap[name] = getCombined(extendingSchema, abstractSchema) as Schema;
} }
@ -129,9 +134,10 @@ function getAbstractCombinedSchemas(schemas: SchemaStubMap): SchemaMap {
return schemaMap; return schemaMap;
} }
function getRegionalCombinedSchemas(countryCode: string): SchemaStubMap { export function getRegionalCombinedSchemas(
const regionalSchemaMap = getRegionalSchema(countryCode); appSchemaMap: SchemaStubMap,
const appSchemaMap = getMapFromList(appSchemas); regionalSchemaMap: SchemaStubMap
): SchemaStubMap {
const combined = { ...appSchemaMap }; const combined = { ...appSchemaMap };
for (const name in regionalSchemaMap) { for (const name in regionalSchemaMap) {
@ -148,7 +154,7 @@ function getRegionalCombinedSchemas(countryCode: string): SchemaStubMap {
return combined; return combined;
} }
function getRegionalSchema(countryCode: string): SchemaStubMap { function getRegionalSchemaMap(countryCode: string): SchemaStubMap {
const countrySchemas = regionalSchemas[countryCode] as const countrySchemas = regionalSchemas[countryCode] as
| SchemaStub[] | SchemaStub[]
| undefined; | undefined;
@ -156,5 +162,5 @@ function getRegionalSchema(countryCode: string): SchemaStubMap {
return {}; return {};
} }
return getMapFromList(countrySchemas); return getMapFromList(countrySchemas, 'name');
} }

View File

@ -1,6 +1,7 @@
import { SchemaStub } from 'schemas/types';
import IndianSchemas from './in'; import IndianSchemas from './in';
/** /**
* Regional Schemas are exported by country code. * Regional Schemas are exported by country code.
*/ */
export default { in: IndianSchemas }; export default { in: IndianSchemas } as Record<string, SchemaStub[]>;

View File

@ -10,6 +10,7 @@
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"sourceMap": true, "sourceMap": true,
"baseUrl": ".", "baseUrl": ".",
"types": ["webpack-env"], "types": ["webpack-env"],
@ -23,8 +24,8 @@
"src/**/*.tsx", "src/**/*.tsx",
"src/**/*.vue", "src/**/*.vue",
"tests/**/*.ts", "schemas/**/*.ts",
"tests/**/*.tsx", "backend/**/*.ts",
"frappe/**/*.ts", "frappe/**/*.ts",
"models/**/*.ts", "models/**/*.ts",