mirror of
https://github.com/frappe/books.git
synced 2024-12-26 12:28:12 +00:00
fix: frappe.registerModels
- Directly register from models object, not models.models - frappe.getModels - Validate model before registering - Fix model.extend bug for duplicate fields - Remove usage of deepmerge and use lodash/cloneDeep
This commit is contained in:
parent
86c57af94b
commit
7198979fc7
53
index.js
53
index.js
@ -1,4 +1,5 @@
|
|||||||
const Observable = require('./utils/observable');
|
const Observable = require('./utils/observable');
|
||||||
|
const utils = require('./utils');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
async init() {
|
async init() {
|
||||||
@ -34,40 +35,36 @@ module.exports = {
|
|||||||
common.initLibs(this);
|
common.initLibs(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
registerModels(models, type) {
|
registerModels(models) {
|
||||||
// register models from app/models/index.js
|
// register models from app/models/index.js
|
||||||
const toAdd = Object.assign({}, models.models);
|
for (let doctype in models) {
|
||||||
|
let metaDefinition = models[doctype];
|
||||||
// post process based on type
|
if (!metaDefinition.name) {
|
||||||
if (models[type]) {
|
throw new Error(`Name is mandatory for ${doctype}`);
|
||||||
models[type](toAdd);
|
}
|
||||||
|
if (metaDefinition.name !== doctype) {
|
||||||
|
throw new Error(
|
||||||
|
`Model name mismatch for ${doctype}: ${metaDefinition.name}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let fieldnames = (metaDefinition.fields || []).map(df => df.fieldname).sort();
|
||||||
|
let duplicateFieldnames = utils.getDuplicates(fieldnames);
|
||||||
|
if (duplicateFieldnames.length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
`Duplicate fields in ${doctype}: ${duplicateFieldnames.join(', ')}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(this.models, toAdd);
|
this.models[doctype] = metaDefinition;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getDoctypeList(filters) {
|
getModels(filterFunction) {
|
||||||
let doctypeList = [];
|
let models = [];
|
||||||
if (filters && Object.keys(filters).length) {
|
for (let doctype in this.models) {
|
||||||
for (let model in this.models) {
|
models.push(this.models[doctype]);
|
||||||
let doctypeName = model;
|
|
||||||
let doctype = this.models[doctypeName];
|
|
||||||
let matchedFields = 0;
|
|
||||||
for (let key in filters) {
|
|
||||||
let field = key;
|
|
||||||
let value = filters[field];
|
|
||||||
|
|
||||||
if (Boolean(doctype[field]) === Boolean(value)) {
|
|
||||||
matchedFields++;
|
|
||||||
}
|
}
|
||||||
}
|
return filterFunction ? models.filter(filterFunction) : models;
|
||||||
|
|
||||||
if (matchedFields === Object.keys(filters).length)
|
|
||||||
doctypeList.push(doctypeName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return doctypeList;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
registerView(view, name, module) {
|
registerView(view, name, module) {
|
||||||
|
@ -1,20 +1,10 @@
|
|||||||
const deepmerge = require('deepmerge');
|
const cloneDeep = require('lodash/cloneDeep');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extend: (base, target, options = {}) => {
|
extend: (base, target, options = {}) => {
|
||||||
base = deepmerge({}, base);
|
base = cloneDeep(base);
|
||||||
const fieldsToMerge = (target.fields || []).map(df => df.fieldname);
|
const fieldsToMerge = (target.fields || []).map(df => df.fieldname);
|
||||||
const fieldsToRemove = options.skipFields || [];
|
const fieldsToRemove = options.skipFields || [];
|
||||||
|
|
||||||
base.fields = base.fields
|
|
||||||
.filter(df => !fieldsToRemove.includes(df.fieldname))
|
|
||||||
.map(df => {
|
|
||||||
if (fieldsToMerge.includes(df.fieldname)) {
|
|
||||||
return deepmerge(df, target.fields.find(tdf => tdf.fieldname === df.fieldname));
|
|
||||||
}
|
|
||||||
return df;
|
|
||||||
});
|
|
||||||
|
|
||||||
const overrideProps = options.overrideProps || [];
|
const overrideProps = options.overrideProps || [];
|
||||||
for (let prop of overrideProps) {
|
for (let prop of overrideProps) {
|
||||||
if (base.hasOwnProperty(prop)) {
|
if (base.hasOwnProperty(prop)) {
|
||||||
@ -22,50 +12,103 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return deepmerge(base, target);
|
let mergeFields = (baseFields, targetFields) => {
|
||||||
|
let fields = cloneDeep(baseFields);
|
||||||
|
fields = fields
|
||||||
|
.filter(df => !fieldsToRemove.includes(df.fieldname))
|
||||||
|
.map(df => {
|
||||||
|
if (fieldsToMerge.includes(df.fieldname)) {
|
||||||
|
let copy = cloneDeep(df);
|
||||||
|
return Object.assign(
|
||||||
|
copy,
|
||||||
|
targetFields.find(tdf => tdf.fieldname === df.fieldname)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return df;
|
||||||
|
});
|
||||||
|
let fieldsAdded = fields.map(df => df.fieldname);
|
||||||
|
let fieldsToAdd = targetFields.filter(
|
||||||
|
df => !fieldsAdded.includes(df.fieldname)
|
||||||
|
);
|
||||||
|
return fields.concat(fieldsToAdd);
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = mergeFields(base.fields, target.fields || []);
|
||||||
|
let out = Object.assign(base, target);
|
||||||
|
out.fields = fields;
|
||||||
|
|
||||||
|
return out;
|
||||||
},
|
},
|
||||||
commonFields: [
|
commonFields: [
|
||||||
{
|
{
|
||||||
fieldname: 'name', fieldtype: 'Data', required: 1
|
fieldname: 'name',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
submittableFields: [
|
||||||
|
{
|
||||||
|
fieldname: 'submitted',
|
||||||
|
fieldtype: 'Check',
|
||||||
|
required: 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
parentFields: [
|
parentFields: [
|
||||||
{
|
{
|
||||||
fieldname: 'owner', fieldtype: 'Data', required: 1
|
fieldname: 'owner',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'modifiedBy', fieldtype: 'Data', required: 1
|
fieldname: 'modifiedBy',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'creation', fieldtype: 'Datetime', required: 1
|
fieldname: 'creation',
|
||||||
|
fieldtype: 'Datetime',
|
||||||
|
required: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'modified', fieldtype: 'Datetime', required: 1
|
fieldname: 'modified',
|
||||||
|
fieldtype: 'Datetime',
|
||||||
|
required: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'keywords', fieldtype: 'Text'
|
fieldname: 'keywords',
|
||||||
|
fieldtype: 'Text'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
childFields: [
|
childFields: [
|
||||||
{
|
{
|
||||||
fieldname: 'idx', fieldtype: 'Int', required: 1
|
fieldname: 'idx',
|
||||||
|
fieldtype: 'Int',
|
||||||
|
required: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'parent', fieldtype: 'Data', required: 1
|
fieldname: 'parent',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'parenttype', fieldtype: 'Data', required: 1
|
fieldname: 'parenttype',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'parentfield', fieldtype: 'Data', required: 1
|
fieldname: 'parentfield',
|
||||||
|
fieldtype: 'Data',
|
||||||
|
required: 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
treeFields: [
|
treeFields: [
|
||||||
{
|
{
|
||||||
fieldname: 'lft', fieldtype: 'Int'
|
fieldname: 'lft',
|
||||||
|
fieldtype: 'Int'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'rgt', fieldtype: 'Int'
|
fieldname: 'rgt',
|
||||||
|
fieldtype: 'Int'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
models: {
|
|
||||||
FilterItem: require('./doctype/FilterItem/FilterItem.js'),
|
FilterItem: require('./doctype/FilterItem/FilterItem.js'),
|
||||||
FilterGroup: require('./doctype/FilterGroup/FilterGroup.js'),
|
FilterGroup: require('./doctype/FilterGroup/FilterGroup.js'),
|
||||||
FilterSelector: require('./doctype/FilterSelector/FilterSelector.js'),
|
FilterSelector: require('./doctype/FilterSelector/FilterSelector.js'),
|
||||||
@ -12,6 +11,5 @@ module.exports = {
|
|||||||
ToDo: require('./doctype/ToDo/ToDo.js'),
|
ToDo: require('./doctype/ToDo/ToDo.js'),
|
||||||
User: require('./doctype/User/User.js'),
|
User: require('./doctype/User/User.js'),
|
||||||
UserRole: require('./doctype/UserRole/UserRole.js'),
|
UserRole: require('./doctype/UserRole/UserRole.js'),
|
||||||
File: require('./doctype/File/File.js'),
|
File: require('./doctype/File/File.js')
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"css-loader": "^1.0.0",
|
"css-loader": "^1.0.0",
|
||||||
"csvjson-csv2json": "5.0.6",
|
"csvjson-csv2json": "5.0.6",
|
||||||
"deepmerge": "^2.1.0",
|
|
||||||
"electron": "5.0.0",
|
"electron": "5.0.0",
|
||||||
"electron-builder": "^21.0.15",
|
"electron-builder": "^21.0.15",
|
||||||
"electron-debug": "^2.0.0",
|
"electron-debug": "^2.0.0",
|
||||||
@ -34,6 +33,7 @@
|
|||||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"knex": "^0.20.3",
|
"knex": "^0.20.3",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
"luxon": "^1.0.0",
|
"luxon": "^1.0.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"morgan": "^1.9.0",
|
"morgan": "^1.9.0",
|
||||||
|
@ -81,6 +81,21 @@ function unique(list, key = it => it) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDuplicates(array) {
|
||||||
|
let duplicates = [];
|
||||||
|
for (let i in array) {
|
||||||
|
let previous = array[i - 1];
|
||||||
|
let current = array[i];
|
||||||
|
|
||||||
|
if (current === previous) {
|
||||||
|
if (!duplicates.includes(current)) {
|
||||||
|
duplicates.push(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return duplicates;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
_,
|
_,
|
||||||
slug,
|
slug,
|
||||||
@ -91,4 +106,5 @@ module.exports = {
|
|||||||
asyncHandler,
|
asyncHandler,
|
||||||
range,
|
range,
|
||||||
unique,
|
unique,
|
||||||
|
getDuplicates
|
||||||
}
|
}
|
@ -1931,11 +1931,6 @@ deep-extend@^0.6.0:
|
|||||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||||
|
|
||||||
deepmerge@^2.1.0:
|
|
||||||
version "2.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
|
|
||||||
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
|
|
||||||
|
|
||||||
default-gateway@^4.2.0:
|
default-gateway@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
|
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
|
||||||
|
Loading…
Reference in New Issue
Block a user