mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
chore: fix types
This commit is contained in:
parent
7514c95883
commit
74bfe7931c
@ -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',
|
||||||
|
@ -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,23 +528,21 @@ 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async #createTable(schemaName: string, tableName?: string) {
|
async #createTable(schemaName: string, tableName?: string) {
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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';
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
|
@ -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[]>;
|
||||||
|
@ -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",
|
||||||
|
Loading…
Reference in New Issue
Block a user