UNPKG

@harishreddym/baqend

Version:

Baqend JavaScript SDK

165 lines (140 loc) 4.99 kB
'use strict'; const BasicType = require('./BasicType'); const EntityType = require('./EntityType'); const EmbeddableType = require('./EmbeddableType'); const ListAttribute = require('./ListAttribute'); const MapAttribute = require('./MapAttribute'); const SetAttribute = require('./SetAttribute'); const SingularAttribute = require('./SingularAttribute'); const PersistentError = require('../error/PersistentError'); /** * @alias metamodel.ModelBuilder */ class ModelBuilder { constructor() { /** @type Object<string,metamodel.ManagedType> */ this.models = {}; /** @type Object<string,Object> */ this.modelDescriptors = null; Object.keys(BasicType).forEach((typeName) => { const basicType = BasicType[typeName]; if (basicType instanceof BasicType) { this.models[basicType.ref] = basicType; } }); } /** * @param {string} ref * @return {metamodel.ManagedType} */ getModel(ref) { if (ref in this.models) { return this.models[ref]; } const model = this.buildModel(ref); this.models[ref] = model; return model; } /** * @param {Object[]} modelDescriptors * @return {Object<string,metamodel.ManagedType>} */ buildModels(modelDescriptors) { this.modelDescriptors = {}; modelDescriptors.forEach((modelDescriptor) => { this.modelDescriptors[modelDescriptor.class] = modelDescriptor; }); Object.keys(this.modelDescriptors).forEach((ref) => { try { const model = this.getModel(ref); this.buildAttributes(model); } catch (e) { throw new PersistentError('Can\'t create model for entity class ' + ref, e); } }); // ensure at least an object entity this.getModel(EntityType.Object.ref); return this.models; } /** * @param {string} ref * @return {metamodel.ManagedType} */ buildModel(ref) { const modelDescriptor = this.modelDescriptors[ref]; let type; if (ref === EntityType.Object.ref) { type = new EntityType.Object(); } else if (modelDescriptor) { if (modelDescriptor.embedded) { type = new EmbeddableType(ref); } else { const superTypeIdentifier = modelDescriptor.superClass || EntityType.Object.ref; type = new EntityType(ref, this.getModel(superTypeIdentifier)); } } else { throw new TypeError('No model available for ' + ref); } type.metadata = {}; if (modelDescriptor) { type.metadata = modelDescriptor.metadata || {}; const permissions = modelDescriptor.acl || {}; Object.keys(permissions).forEach((permission) => { type[permission + 'Permission'].fromJSON(permissions[permission]); }); } return type; } /** * @param {metamodel.EntityType} model * @return {void} */ buildAttributes(model) { const modelDescriptor = this.modelDescriptors[model.ref]; const fields = modelDescriptor.fields; Object.keys(fields).forEach((name) => { const field = fields[name]; if (!model.getAttribute(name)) { // skip predefined attributes model.addAttribute(this.buildAttribute(field), field.order); } }); if (modelDescriptor.validationCode) { model.validationCode = modelDescriptor.validationCode; } } /** * @param {Object} field The field metadata * @param {string} field.name The name of zhe field * @param {string} field.type The type reference of the field * @param {number} field.order The order number of the field * @param {Object<string,*>} field.metadata Additional metadata of the field * @return {metamodel.Attribute} */ buildAttribute(field) { // TODO: remove readonly if createdAt and updatedAt becomes real metadata fields in the schema const isMetadata = field.flags && (field.flags.indexOf('METADATA') !== -1 || field.flags.indexOf('READONLY') !== -1); const name = field.name; const ref = field.type; if (ref.indexOf('/db/collection.') !== 0) { const singularAttribute = new SingularAttribute(name, this.getModel(ref), isMetadata); singularAttribute.metadata = field.metadata; return singularAttribute; } const collectionType = ref.substring(0, ref.indexOf('[')); const elementType = ref.substring(ref.indexOf('[') + 1, ref.indexOf(']')).trim(); switch (collectionType) { case ListAttribute.ref: return new ListAttribute(name, this.getModel(elementType)); case SetAttribute.ref: return new SetAttribute(name, this.getModel(elementType)); case MapAttribute.ref: { const keyType = elementType.substring(0, elementType.indexOf(',')).trim(); const valueType = elementType.substring(elementType.indexOf(',') + 1).trim(); return new MapAttribute(name, this.getModel(keyType), this.getModel(valueType)); } default: throw new TypeError('No collection available for ' + ref); } } } module.exports = ModelBuilder;