UNPKG

breeze-sequelize

Version:
168 lines 7.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const breeze_client_1 = require("breeze-client"); const sequelize_1 = require("sequelize"); const _ = require("lodash"); const utils = require("./utils"); const log = utils.log; // TODO: still need to handle inherited entity types - TPT /** Maps Breeze metadata to Sequelize Models */ class MetadataMapper { constructor(breezeMetadata, sequelize) { this.sequelize = sequelize; let ms; if (breezeMetadata instanceof breeze_client_1.MetadataStore) { ms = breezeMetadata; } else { ms = new breeze_client_1.breeze.MetadataStore(); ms.importMetadata(breezeMetadata); } this.metadataStore = ms; this._createMaps(); } /** creates entityTypeSqModelMap and resourceNameSqModelMap */ _createMaps() { const ms = this.metadataStore; const allTypes = ms.getEntityTypes(); const typeMap = _.groupBy(allTypes, t => { return t.isComplexType ? "complexType" : "entityType"; }); // let complexTypes = typeMap["complexType"]; const entityTypes = typeMap["entityType"]; // map of entityTypeName to sqModel const entityTypeSqModelMap = this.entityTypeSqModelMap = {}; // first create all of the sequelize types with just data properties entityTypes.forEach(entityType => { const typeConfig = this.mapToSqModelConfig(entityType); const modelName = entityType.shortName; // find model in sequelize instance, else create model let sqModel; if (this.sequelize.isDefined(modelName)) { log("model already defined: ", modelName); sqModel = this.sequelize.model(modelName); } else { const options = { // NOTE: case sensitivity of the table name may not be the same on some sql databases. modelName: modelName, }; log("model not defined: ", modelName); sqModel = this.sequelize.define(modelName, typeConfig, options); } entityTypeSqModelMap[entityType.name] = sqModel; }, this); // now add navigation props this.createNavProps(entityTypes, entityTypeSqModelMap); // map of breeze resourceName to sequelize model this.resourceNameSqModelMap = _.mapValues(ms._resourceEntityTypeMap, (value, key) => { return entityTypeSqModelMap[value]; }); } // source.fn(target, { foreignKey: }) // hasOne - adds a foreign key to target // belongsTo - add a foreign key to source // hasMany - adds a foreign key to target, unless you also specifiy that target hasMany source, in which case a junction table is created with sourceId and targetId /** Adds relationships to the Models based on Breeze NavigationProperties */ createNavProps(entityTypes, entityTypeSqModelMap) { // TODO: we only support single column foreignKeys for now. entityTypes.forEach(entityType => { const navProps = entityType.navigationProperties; const sqModel = entityTypeSqModelMap[entityType.name]; navProps.forEach(np => { const npName = np.nameOnServer; if (sqModel.associations[npName]) { // already mapped return; } const targetEntityType = np.entityType; const targetSqModel = entityTypeSqModelMap[targetEntityType.name]; if (np.isScalar) { if (np.foreignKeyNamesOnServer.length > 0) { sqModel.belongsTo(targetSqModel, { as: npName, foreignKey: np.foreignKeyNamesOnServer[0], onDelete: "no action" }); // Product, Category } else { sqModel.hasOne(targetSqModel, { as: npName, foreignKey: np.invForeignKeyNamesOnServer[0], onDelete: "no action" }); // Order, InternationalOrder } } else { if (np.foreignKeyNamesOnServer.length > 0) { throw new Error("not sure what kind of reln this is"); // sqModel.hasMany(targetSqModel, { as: npName, foreignKey: np.foreignKeyNamesOnServer[0]}) } else { sqModel.hasMany(targetSqModel, { as: npName, foreignKey: np.invForeignKeyNamesOnServer[0], onDelete: "no action" }); // Category, Product } } }); }); } /** Creates a set of Sequelize attributes based on DataProperties */ mapToSqModelConfig(entityOrComplexType) { // propConfig looks like // { firstProp: { type: Sequelize.XXX, ... }, // secondProp: { type: Sequelize.XXX, ... } // .. // } const typeConfig = {}; entityOrComplexType.dataProperties.forEach(dataProperty => { const propConfig = this.mapToSqPropConfig(dataProperty); _.merge(typeConfig, propConfig); }); return typeConfig; } /** Creates Sequelize column attributes based on a DataProperty */ mapToSqPropConfig(dataProperty) { if (dataProperty.isComplexProperty) { return this.mapToSqModelConfig(dataProperty.dataType); } const propConfig = {}; const attributes = {}; propConfig[dataProperty.nameOnServer] = attributes; const sqModel = _dataTypeMap[dataProperty.dataType.name]; if (sqModel == null) { const template = _.template("Unable to map the dataType '${ dataType }' of dataProperty: '${ dataProperty }'"); throw new Error(template({ dataProperty: dataProperty.parentType.shortName + "." + dataProperty.name, dataType: dataProperty.dataType.name })); } attributes.type = sqModel; if (dataProperty.dataType === breeze_client_1.breeze.DataType.String && dataProperty.maxLength) { attributes.type = sequelize_1.DataTypes.STRING(dataProperty.maxLength); } if (!dataProperty.isNullable) { attributes.allowNull = false; } if (dataProperty.isPartOfKey) { attributes.primaryKey = true; if (dataProperty.parentType.autoGeneratedKeyType === breeze_client_1.breeze.AutoGeneratedKeyType.Identity) { const dt = attributes.type; if (dt.key === "INTEGER" || dt.key === "BIGINT") { attributes.autoIncrement = true; } } } if (dataProperty.defaultValue !== undefined && !dataProperty.isPartOfKey) { // if (dataProperty.defaultValue !== undefined) { attributes.defaultValue = dataProperty.defaultValue; } return propConfig; } } exports.MetadataMapper = MetadataMapper; const _dataTypeMap = { String: sequelize_1.DataTypes.STRING, Boolean: sequelize_1.DataTypes.BOOLEAN, DateTime: sequelize_1.DataTypes.DATE, DateTimeOffset: sequelize_1.DataTypes.DATE, Byte: sequelize_1.DataTypes.TINYINT.UNSIGNED, Int16: sequelize_1.DataTypes.SMALLINT, Int32: sequelize_1.DataTypes.INTEGER, Int64: sequelize_1.DataTypes.BIGINT, Decimal: sequelize_1.DataTypes.DECIMAL(19, 4), Double: sequelize_1.DataTypes.DOUBLE, Single: sequelize_1.DataTypes.FLOAT, Guid: sequelize_1.DataTypes.UUID, Binary: sequelize_1.DataTypes.STRING().BINARY, Time: sequelize_1.DataTypes.STRING, Undefined: sequelize_1.DataTypes.BLOB }; //# sourceMappingURL=MetadataMapper.js.map