Socket
Socket
Sign inDemoInstall

breeze-sequelize

Package Overview
Dependencies
25
Maintainers
5
Versions
18
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.0 to 0.4.0

index.js

70

dbUtils.js

@@ -1,40 +0,40 @@

var Sequelize = require('sequelize');
var Promise = require('bluebird');
var utils = require('./utils.js');
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var sequelize_1 = require("sequelize");
var utils = require('./utils.js');
var log = utils.log;
exports.connect = connect;
exports.createDb = createDb;
// returns a Promise(connection)
/** @returns Promise<"success"> or throws an error */
function connect(dbConfig, sequelizeOptions) {
var sequelize = new Sequelize(dbConfig.dbName, dbConfig.user, dbConfig.password, sequelizeOptions);
var statement = 'SELECT 1';
return sequelize.query(statement, { type: sequelize.QueryTypes.RAW}).then(function(results) {
log("Connected to database: " + dbConfig.dbName);
return "success";
}).error(function(err) {
log("Database error: " + dbConfig.dbName + " error: " + err.message);
throw err;
});
};
// return promise(null);
var sequelize = new sequelize_1.Sequelize(dbConfig.dbName, dbConfig.user, dbConfig.password, sequelizeOptions);
var statement = 'SELECT 1';
return sequelize.query(statement, { type: sequelize_1.QueryTypes.RAW }).then(function (results) {
log("Connected to database: " + dbConfig.dbName);
return "success";
}).error(function (err) {
log("Database error: " + dbConfig.dbName + " error: " + err.message);
throw err;
});
}
exports.connect = connect;
;
/** @returns Promise<void> or throws an error */
function createDb(dbConfig, sequelizeOptions) {
var sequelize = new Sequelize(null, dbConfig.user, dbConfig.password, sequelizeOptions);
var statement = 'CREATE DATABASE ' + dbConfig.dbName;
return sequelize.query(statement, { type: sequelize.QueryTypes.RAW}).then(function() {
log("Database created: " + dbConfig.dbName);
}).error(function(err) {
if (err.message && err.message.indexOf("ER_DB_CREATE_EXISTS") >= 0) {
log("Database already exists: " + dbConfig.dbName);
} else {
log("Database creation error: " + dbConfig.dbName + " error: " + err.message);
throw err;
}
});
};
var sequelize = new sequelize_1.Sequelize(null, dbConfig.user, dbConfig.password, sequelizeOptions);
var statement = 'CREATE DATABASE ' + dbConfig.dbName;
return sequelize.query(statement, { type: sequelize_1.QueryTypes.RAW }).then(function () {
log("Database created: " + dbConfig.dbName);
}).error(function (err) {
if (err.message && err.message.indexOf("ER_DB_CREATE_EXISTS") >= 0) {
log("Database already exists: " + dbConfig.dbName);
}
else {
log("Database creation error: " + dbConfig.dbName + " error: " + err.message);
throw err;
}
});
}
exports.createDb = createDb;
;
// old version using node 'next' semantics.

@@ -56,2 +56,2 @@ // next => function(err, connection);

//}
//# sourceMappingURL=dbUtils.js.map

@@ -1,10 +0,17 @@

exports.SequelizeQuery = require("./SequelizeQuery.json.js");
exports.SequelizeManager = require("./SequelizeManager.js");
exports.SequelizeSaveHandler = require("./SequelizeSaveHandler.js");
exports.utils = require("./utils.js");
exports.dbUtils = require("./dbUtils");
exports.breeze = require("breeze-client"); // needed because we have augmented breeze in the SequelizeQuery component
exports.Sequelize = exports.SequelizeManager.Sequelize;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var SequelizeQuery_1 = require("./SequelizeQuery");
exports.SequelizeQuery = SequelizeQuery_1.SequelizeQuery;
var SequelizeManager_1 = require("./SequelizeManager");
exports.SequelizeManager = SequelizeManager_1.SequelizeManager;
var SequelizeSaveHandler_1 = require("./SequelizeSaveHandler");
exports.SequelizeSaveHandler = SequelizeSaveHandler_1.SequelizeSaveHandler;
var utils = require("./utils");
exports.utils = utils;
var dbUtils = require("./dbUtils");
exports.dbUtils = dbUtils;
var breeze_client_1 = require("breeze-client");
exports.breeze = breeze_client_1.breeze;
var Sequelize = SequelizeManager_1.SequelizeManager.Sequelize;
exports.Sequelize = Sequelize;
//# sourceMappingURL=main.js.map

@@ -1,161 +0,158 @@

var Sequelize = require('sequelize');
var _ = require('lodash');
var breeze = require("breeze-client");
var utils = require('./utils.js');
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var breeze_client_1 = require("breeze-client");
var sequelize_1 = require("sequelize");
var _ = require("lodash");
var utils = require("./utils");
var log = utils.log;
;
// TODO: still need to handle inherited entity types - TPT
module.exports = MetadataMapper = function(breezeMetadata, sequelize) {
this.sequelize = sequelize;
var ms;
if (breezeMetadata instanceof breeze.MetadataStore) {
ms = breezeMetadata;
} else {
var ms = new breeze.MetadataStore();
ms.importMetadata(breezeMetadata);
}
this.metadataStore = ms;
this._createMaps();
}
MetadataMapper.prototype._createMaps = function() {
// creates entityTypeSqModelMap and resourceNameSqModelMap
var ms = this.metadataStore;
var allTypes = ms.getEntityTypes();
var typeMap = _.groupBy(allTypes, function(t) {
return t.isComplexType ? "complexType" : "entityType";
});
var complexTypes = typeMap["complexType"];
var entityTypes = typeMap["entityType"];
// map of entityTypeName to sqModel
var entityTypeSqModelMap = this.entityTypeSqModelMap = {};
// first create all of the sequelize types with just data properties
entityTypes.forEach(function(entityType) {
var typeConfig = mapToSqModelConfig(this, entityType);
var options = {
// NOTE: case sensitivity of the table name may not be the same on some sql databases.
modelName: entityType.shortName, // this will define the table's name; see options.define
/** Maps Breeze metadata to Sequelize Models */
var MetadataMapper = /** @class */ (function () {
function MetadataMapper(breezeMetadata, sequelize) {
this.sequelize = sequelize;
var 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 */
MetadataMapper.prototype._createMaps = function () {
var _this = this;
var ms = this.metadataStore;
var allTypes = ms.getEntityTypes();
var typeMap = _.groupBy(allTypes, function (t) {
return t.isComplexType ? "complexType" : "entityType";
});
// let complexTypes = typeMap["complexType"];
var entityTypes = typeMap["entityType"];
// map of entityTypeName to sqModel
var entityTypeSqModelMap = this.entityTypeSqModelMap = {};
// first create all of the sequelize types with just data properties
entityTypes.forEach(function (entityType) {
var typeConfig = _this.mapToSqModelConfig(entityType);
var options = {
// NOTE: case sensitivity of the table name may not be the same on some sql databases.
modelName: entityType.shortName,
};
var sqModel = _this.sequelize.define(entityType.shortName, 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, function (value, key) {
return entityTypeSqModelMap[value];
});
};
var sqModel = this.sequelize.define(entityType.shortName, typeConfig, options);
entityTypeSqModelMap[entityType.name] = sqModel;
}, this);
// now add navigation props
createNavProps(entityTypes, entityTypeSqModelMap);
// map of breeze resourceName to sequelize model
this.resourceNameSqModelMap = _.mapValues(ms._resourceEntityTypeMap, function(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
// entityTypeMap is a map of entityType.name to sequelize model
function createNavProps(entityTypes, entityTypeSqModelMap) {
// TODO: we only support single column foreignKeys for now.
entityTypes.forEach(function(entityType) {
var navProps = entityType.navigationProperties;
var sqModel = entityTypeSqModelMap[entityType.name];
navProps.forEach(function(np) {
var npName = np.nameOnServer;
var targetEntityType = np.entityType;
var 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
// 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 */
MetadataMapper.prototype.createNavProps = function (entityTypes, entityTypeSqModelMap) {
// TODO: we only support single column foreignKeys for now.
entityTypes.forEach(function (entityType) {
var navProps = entityType.navigationProperties;
var sqModel = entityTypeSqModelMap[entityType.name];
navProps.forEach(function (np) {
var npName = np.nameOnServer;
var targetEntityType = np.entityType;
var 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 */
MetadataMapper.prototype.mapToSqModelConfig = function (entityOrComplexType) {
// propConfig looks like
// { firstProp: { type: Sequelize.XXX, ... },
// secondProp: { type: Sequelize.XXX, ... }
// ..
// }
var _this = this;
var typeConfig = {};
entityOrComplexType.dataProperties.forEach(function (dataProperty) {
var propConfig = _this.mapToSqPropConfig(dataProperty);
_.merge(typeConfig, propConfig);
});
return typeConfig;
};
/** Creates Sequelize column attributes based on a DataProperty */
MetadataMapper.prototype.mapToSqPropConfig = function (dataProperty) {
if (dataProperty.isComplexProperty) {
return this.mapToSqModelConfig(dataProperty.dataType);
}
} 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
var propConfig = {};
var attributes = {};
propConfig[dataProperty.nameOnServer] = attributes;
var sqModel = _dataTypeMap[dataProperty.dataType.name];
if (sqModel == null) {
var 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 }));
}
}
});
});
}
function mapToSqModelConfig(mapper, entityOrComplexType) {
// propConfig looks like
// { firstProp: { type: Sequelize.XXX, ... },
// secondProp: { type: Sequelize.XXX, ... }
// ..
// }
var typeConfig = {};
entityOrComplexType.dataProperties.forEach(function(dataProperty) {
var propConfig = mapToSqPropConfig(mapper, dataProperty);
_.merge(typeConfig, propConfig);
});
return typeConfig;
}
function mapToSqPropConfig(mapper, dataProperty) {
if (dataProperty.isComplexProperty) {
return mapToSqModelConfig(mapper, dataProperty.dataType);
}
var propConfig = {};
var attributes = {};
propConfig[dataProperty.nameOnServer] = attributes;
var sqModel = _dataTypeMap[dataProperty.dataType.name];
if (sqModel == null) {
var 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.DataType.String && dataProperty.maxLength) {
attributes.type = Sequelize.STRING(dataProperty.maxLength);
}
if (!dataProperty.isNullable) {
attributes.allowNull = false;
}
if (dataProperty.isPartOfKey) {
attributes.primaryKey = true;
if (dataProperty.parentType.autoGeneratedKeyType == breeze.AutoGeneratedKeyType.Identity) {
if (attributes.type.key == "INTEGER" || attributes.type.key == "BIGINT") {
attributes.autoIncrement = true;
}
}
}
if (dataProperty.defaultValue !== undefined && !dataProperty.isPartOfKey) {
// if (dataProperty.defaultValue !== undefined) {
attributes.defaultValue = dataProperty.defaultValue;
}
return propConfig;
}
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) {
var 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;
};
return MetadataMapper;
}());
exports.MetadataMapper = MetadataMapper;
var _dataTypeMap = {
String: Sequelize.STRING,
Boolean: Sequelize.BOOLEAN,
DateTime: Sequelize.DATE,
DateTimeOffset: Sequelize.DATE,
Byte: Sequelize.INTEGER.UNSIGNED,
Int16: Sequelize.INTEGER,
Int32: Sequelize.INTEGER,
Int64: Sequelize.BIGINT,
Decimal: Sequelize.DECIMAL(19,4),
Double: Sequelize.FLOAT,
Single: Sequelize.FLOAT,
Guid: Sequelize.UUID,
Binary: Sequelize.STRING.BINARY,
Time: Sequelize.STRING,
Undefined: Sequelize.BLOB
};
String: sequelize_1.DataTypes.STRING,
Boolean: sequelize_1.DataTypes.BOOLEAN,
DateTime: sequelize_1.DataTypes.DATE,
DateTimeOffset: sequelize_1.DataTypes.DATE,
Byte: sequelize_1.DataTypes.INTEGER.UNSIGNED,
Int16: sequelize_1.DataTypes.INTEGER,
Int32: sequelize_1.DataTypes.INTEGER,
Int64: sequelize_1.DataTypes.BIGINT,
Decimal: sequelize_1.DataTypes.DECIMAL(19, 4),
Double: sequelize_1.DataTypes.FLOAT,
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
{
"name": "breeze-sequelize",
"version": "0.3.0",
"version": "0.4.0",
"description": "Breeze Sequelize server implementation",

@@ -10,2 +10,3 @@ "keywords": [

"query",
"relational",
"linq",

@@ -15,16 +16,29 @@ "graph"

"main": "main.js",
"types": "types/main.d.ts",
"files": [
"*.js",
"types/*"
],
"directories": {},
"dependencies": {
"bluebird": "^3.5.5",
"breeze-client": "^1.7.2",
"bluebird": "^3.7.2",
"breeze-client": ">=2.0.3",
"lodash": "^4.17.15",
"sequelize": "^5.18.1",
"sequelize": "^5.21.3",
"toposort": "^2.0.2"
},
"devDependencies": {
"@types/bluebird": "^3.5.29",
"@types/lodash": "^4.14.137",
"@types/node": "^12.12.25",
"@types/validator": "^12.0.1",
"chai": "^4.2.0",
"mocha": "^6.2.0"
"mocha": "^6.2.0",
"rimraf": "^3.0.0",
"typescript": "~3.4.5"
},
"scripts": {
"test": "mocha"
"test": "mocha",
"build": "tsc && npm pack",
"clean": "rimraf *.js && rimraf *.map && rimraf types"
},

@@ -31,0 +45,0 @@ "repository": {

@@ -1,5 +0,12 @@

# The "breeze-sequelize" npm package
# breeze-sequelize
This is the official NPM package for the Breeze Sequelize integration. The package files are in the [breeze.server.node](https://github.com/Breeze/breeze.server.node "github: "breeze-server-node") repository in the 'breeze-sequelize' subfolder.
The `breeze-sequelize` library lets you easily build a Sequelize server for managing relational data.
Starting with Breeze metadata, it will create the Sequelize model for you, and Sequelize can create a database from the model.
Once you have the model and database, `breeze-sequelize` makes it easy to query and update data from your Breeze client.
## Install
To install with npm, open a terminal or command window and enter:

@@ -6,0 +13,0 @@

@@ -1,86 +0,78 @@

var Sequelize = require('sequelize');
var breeze = require("breeze-client");
var Promise = require("bluebird");
var _ = require('lodash');
var MetadataMapper = require('./MetadataMapper.js');
var dbUtils = require('./dbUtils.js');
var utils = require('./utils.js');
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var sequelize_1 = require("sequelize");
var dbUtils_1 = require("./dbUtils");
var MetadataMapper_1 = require("./MetadataMapper");
var _ = require("lodash");
var utils = require("./utils");
var log = utils.log;
module.exports = SequelizeManager;
function SequelizeManager(dbConfig, sequelizeOptions) {
var defaultOptions = {
dialect: "mysql", // or 'sqlite', 'postgres', 'mariadb'
port: 3306, // or 5432 (for postgres)
// omitNull: true,
logging: console.log,
dialectOptions: { decimalNumbers: true },
define: {
freezeTableName: true, // prevent sequelize from pluralizing table names
timestamps: false // deactivate the timestamp columns (createdAt, etc.)
}
};
var define = defaultOptions.define;
this.sequelizeOptions = _.extend(defaultOptions, sequelizeOptions || {});
this.sequelizeOptions.define = _.extend(define, (sequelizeOptions && sequelizeOptions.define) || {});
this.dbConfig = dbConfig;
this.sequelize = new Sequelize(dbConfig.dbName, dbConfig.user, dbConfig.password, this.sequelizeOptions);
}
// Expose Sequelize from outside
SequelizeManager.Sequelize = Sequelize;
// returns Promise(null);
SequelizeManager.prototype.authenticate = function() {
// check database connection
return this.sequelize.authenticate().then(function() {
log('Connection has been established successfully.');
}).error(function(err) {
log('Unable to connect to the database:', err);
throw err;
});
};
SequelizeManager.prototype.createDb = function() {
return dbUtils.createDb(this.dbConfig, this.sequelizeOptions);
};
SequelizeManager.prototype.importMetadata = function(breezeMetadata) {
var metadataMapper = new MetadataMapper(breezeMetadata, this.sequelize);
// TODO: should we merge here instead ; i.e. allow multiple imports...
this.models = this.resourceNameSqModelMap = metadataMapper.resourceNameSqModelMap;
this.entityTypeSqModelMap = metadataMapper.entityTypeSqModelMap;
this.metadataStore = metadataMapper.metadataStore;
};
// returns Promise(sequelize);
SequelizeManager.prototype.sync = function(shouldCreateDb, sequelizeOpts) {
if (shouldCreateDb) {
var that = this;
return this.createDb().then(function() {
return syncCore(that.sequelize, sequelizeOpts);
});
} else {
return syncCore(this.sequelize, sequelizeOpts);
}
};
// returns Promise(sequelize);
function syncCore(sequelize, sequelizeOpts) {
var defaultOptions = { force: true };
sequelizeOpts = _.extend(defaultOptions, sequelizeOpts || {});
return sequelize.sync(sequelizeOpts).then(function() {
log("schema created");
return sequelize;
}).catch(function(err) {
console.log("schema creation failed");
throw err;
});
}
/** Manages the Sequelize instance for Breeze query and save operations */
var SequelizeManager = /** @class */ (function () {
function SequelizeManager(dbConfig, sequelizeOptions) {
var defaultOptions = {
dialect: "mysql",
port: 3306,
// omitNull: true,
logging: console.log,
dialectOptions: { decimalNumbers: true },
define: {
freezeTableName: true,
timestamps: false // deactivate the timestamp columns (createdAt, etc.)
}
};
var define = defaultOptions.define;
this.sequelizeOptions = _.extend(defaultOptions, sequelizeOptions || {});
this.sequelizeOptions.define = _.extend(define, (sequelizeOptions && sequelizeOptions.define) || {});
this.dbConfig = dbConfig;
this.sequelize = new sequelize_1.Sequelize(dbConfig.dbName, dbConfig.user, dbConfig.password, this.sequelizeOptions);
}
/** Connect to the database */
SequelizeManager.prototype.authenticate = function () {
// check database connection
return this.sequelize.authenticate().then(function () {
log('Connection has been established successfully.');
}).error(function (err) {
log('Unable to connect to the database:', err);
throw err;
});
};
/** Create a new database */
SequelizeManager.prototype.createDb = function () {
return dbUtils_1.createDb(this.dbConfig, this.sequelizeOptions);
};
/** Convert Breeze metadata to Sequelize models */
SequelizeManager.prototype.importMetadata = function (breezeMetadata) {
var metadataMapper = new MetadataMapper_1.MetadataMapper(breezeMetadata, this.sequelize);
// TODO: should we merge here instead ; i.e. allow multiple imports...
this.models = this.resourceNameSqModelMap = metadataMapper.resourceNameSqModelMap;
this.entityTypeSqModelMap = metadataMapper.entityTypeSqModelMap;
this.metadataStore = metadataMapper.metadataStore;
};
/** Sync the Sequelize model with the database */
SequelizeManager.prototype.sync = function (shouldCreateDb, sequelizeOpts) {
var _this = this;
if (shouldCreateDb) {
return this.createDb().then(function () {
return _this.syncCore(_this.sequelize, sequelizeOpts);
});
}
else {
return this.syncCore(this.sequelize, sequelizeOpts);
}
};
SequelizeManager.prototype.syncCore = function (sequelize, sequelizeOpts) {
var defaultOptions = { force: true };
sequelizeOpts = _.extend(defaultOptions, sequelizeOpts || {});
return sequelize.sync(sequelizeOpts).then(function () {
log("schema created");
return sequelize;
}).catch(function (err) {
console.log("schema creation failed");
throw err;
});
};
SequelizeManager.Sequelize = sequelize_1.Sequelize;
return SequelizeManager;
}());
exports.SequelizeManager = SequelizeManager;
//# sourceMappingURL=SequelizeManager.js.map

@@ -1,530 +0,402 @@

var Sequelize = require('sequelize');
var Promise = require("bluebird");
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var bluebird_1 = require("bluebird");
var _ = require("lodash");
var SaveMap_1 = require("./SaveMap");
var toposort = require("toposort");
var _ = require('lodash');
// TODO: transactions
// server side validations
// check SaveMap api for consistency with the rest of breeze.
module.exports = SequelizeSaveHandler;
function SequelizeSaveHandler(sequelizeManager, req) {
var reqBody = req.body;
this.sequelizeManager = sequelizeManager;
this.metadataStore = sequelizeManager.metadataStore;
this.entitiesFromClient = reqBody.entities;
this.saveOptions = reqBody.saveOptions;
this._keyMappings = [];
this._fkFixupMap = {};
this._savedEntities = [];
this.keyGenerator = sequelizeManager.keyGenerator;
// this._entitiesCreatedOnServer = [];
};
var ctor = SequelizeSaveHandler;
ctor.save = function(sequelizeManager, req ) {
var saveHandler = new SequelizeSaveHandler(sequelizeManager, req);
return saveHandler.save();
};
// virtual method - returns boolean
//ctor.prototype.beforeSaveEntity = function(entityInfo)
// virtual method - returns nothing
//ctor.prototype.beforeSaveEntities = function(saveMap)
ctor.prototype.save = function() {
var beforeSaveEntity = (this.beforeSaveEntity || noopBeforeSaveEntity).bind(this);
var entityTypeMap = {};
var entityInfos = this.entitiesFromClient.map(function(entity) {
// transform entities from how they are sent from the client
// into entityInfo objects which is how they are exposed
// to interception on the server.
var entityAspect = entity.entityAspect;
var entityTypeName = entityAspect.entityTypeName;
var entityType = entityTypeMap[entityTypeName];
if (!entityType) {
entityType = this.metadataStore.getEntityType(entityTypeName);
if (entityType) {
entityTypeMap[entityTypeName] = entityType;
} else {
throw new Error("Unable to locate server side metadata for an EntityType named: " + entityTypeName);
}
/** Handles saving entities from Breeze SaveChanges requests */
var SequelizeSaveHandler = /** @class */ (function () {
/** Create an instance for the given save request */
function SequelizeSaveHandler(sequelizeManager, req) {
var reqBody = req.body;
this.sequelizeManager = sequelizeManager;
this.metadataStore = sequelizeManager.metadataStore;
this.entitiesFromClient = reqBody.entities;
this.saveOptions = reqBody.saveOptions;
this._keyMappings = [];
this._fkFixupMap = {};
this._savedEntities = [];
this.keyGenerator = sequelizeManager.keyGenerator;
}
var unmapped = entity.__unmapped;
var ei = { entity: entity, entityType: entityType, entityAspect: entityAspect, unmapped: unmapped };
// just to be sure that we don't try to send it to the db server or return it to the client.
delete entity.entityAspect;
return ei;
}, this);
// create the saveMap (entities to be saved) grouped by entityType
var saveMapData = _.groupBy(entityInfos, function(entityInfo) {
// _.groupBy will bundle all undefined returns together.
if (beforeSaveEntity(entityInfo)) {
return entityInfo.entityType.name;
}
});
// remove the entries where beforeSaveEntity returned false ( they are all grouped under 'undefined'
delete saveMapData["undefined"];
// want to have SaveMap functions available
var saveMap = _.extend(new SaveMap(this), saveMapData);
return this._saveWithTransaction(saveMap);
};
ctor.prototype._saveWithTransaction = function(saveMap) {
var that = this;
var sequelize = this.sequelizeManager.sequelize;
return sequelize.transaction().then(function(trx) {
that.transaction = trx;
var nextPromise;
var beforeSaveEntities = (that.beforeSaveEntities || noopBeforeSaveEntities).bind(that);
// beforeSaveEntities will either return nothing or a promise.
nextPromise = Promise.resolve(beforeSaveEntities(saveMap, trx));
// saveCore returns either a list of entities or an object with an errors property.
return nextPromise.then(function () {
return that._saveCore(saveMap, trx);
}).then(function (r) {
if (r.errors) {
trx.rollback();
return r;
} else {
trx.commit();
return { entities: r, keyMappings: that._keyMappings };
}
}).catch(function (e) {
trx.rollback();
throw e;
});
});
};
// will be bound to SequelizeSaveHandler instance at runtime.
ctor.prototype._saveCore = function(saveMap, transaction) {
var that = this;
if (saveMap.entityErrors || saveMap.errorMessage) {
return Promise.resolve({ errors: saveMap.entityErrors || [], message: saveMap.errorMessage });
}
var entityTypes = _.keys(saveMap).map(function (entityTypeName) {
// guaranteed to succeed because these have all been looked up earlier.
return this.metadataStore.getEntityType(entityTypeName);
}, this);
var sortedEntityTypes = toposortEntityTypes(entityTypes);
var entityGroups = sortedEntityTypes.map(function (entityType) {
return { entityType: entityType, entityInfos: saveMap[entityType.name] };
});
// do adds/updates first followed by deletes in reverse order.
// add/updates come first because we might move children off of a parent before deleting the parent
// and we don't want to cause a constraint exception by deleting the parent before all of its
// children have been moved somewhere else.
return Promise.reduce(entityGroups, function (savedEntities, entityGroup) {
return that._processEntityGroup(entityGroup, transaction, false).then(function (entities) {
Array.prototype.push.apply(savedEntities, entities);
return savedEntities;
});
}, []).then(function (entitiesHandledSoFar) {
return Promise.reduce(entityGroups.reverse(), function (savedEntities, entityGroup) {
return that._processEntityGroup(entityGroup, transaction, true).then(function (entities) {
Array.prototype.push.apply(savedEntities, entities);
return savedEntities;
});
}, entitiesHandledSoFar);
});
}
// Need to handle
// entityKey._id may be null/undefined for entities created only on the server side - so no need for keyMapping
// returns a promise containing resultEntities array when all entities within the group have been saved.
ctor.prototype._processEntityGroup = function(entityGroup, transaction, processDeleted) {
var entityType = entityGroup.entityType;
var entityInfos = entityGroup.entityInfos.filter(function(entityInfo) {
var isDeleted = entityInfo.entityAspect.entityState == "Deleted"
return processDeleted ? isDeleted : !isDeleted;
});
var sqModel = this.sequelizeManager.entityTypeSqModelMap[entityType.name];
// Promise.reduce(["file1.txt", "file2.txt", "file3.txt"], function(total, fileName) {
// return fs.readFileAsync(fileName, "utf8").then(function(contents) {
// return total + parseInt(contents, 10);
// });
// }, 0).then(function(total) {
// //Total is 30
// });
entityInfos = toposortEntityInfos(entityType, entityInfos);
if (processDeleted)
entityInfos = entityInfos.reverse();
var that = this;
return Promise.reduce(entityInfos, function(savedEntities, entityInfo) {
// function returns a promise for this entity
// and updates the results array.
return that._saveEntityAsync(entityInfo, sqModel, transaction).then(function(savedEntity) {
savedEntities.push(savedEntity);
return savedEntities;
});
}, []);
};
// returns a promise with the saved entity
ctor.prototype._saveEntityAsync = function(entityInfo, sqModel, transaction) {
// function returns a promise for this entity
// and updates the results array.
var that = this;
// not a "real" entityAspect - just the salient pieces sent from the client.
var entity = entityInfo.entity;
var entityAspect = entityInfo.entityAspect;
var entityType = entityInfo.entityType;
var entityTypeName = entityType.name;
// TODO: determine if this is needed because we need to strip the entityAspect off the entity for inserts.
entityAspect.entity = entity;
// TODO: we really only need to coerce every field on an insert
// only selected fields are needed for update and delete.
this._coerceData(entity, entityType);
var keyProperties = entityType.keyProperties;
var firstKeyPropName = keyProperties[0].nameOnServer;
var entityState = entityAspect.entityState;
var trxOptions = { transaction: transaction };
var promise;
if (entityState === "Added") {
var keyMapping = null;
// NOTE: there are two instances of autoGeneratedKeyType available
// one on entityType which is part of the metadata and a second
// on the entityAspect that was sent as part of the save.
// The one on the entityAspect "overrides" the one on the entityType.
var autoGeneratedKey = entityAspect.autoGeneratedKey;
var autoGeneratedKeyType = autoGeneratedKey && autoGeneratedKey.autoGeneratedKeyType;
if (autoGeneratedKeyType && autoGeneratedKeyType !== "None") {
var realKeyValue;
var tempKeyValue = entity[firstKeyPropName];
if (autoGeneratedKeyType == "KeyGenerator") {
if (this.keyGenerator == null) {
throw new Error("No KeyGenerator was provided for property:" + keyProperties[0].name + " on entityType: " + entityType.name);
/** Save the entities in the save request */
SequelizeSaveHandler.prototype.save = function () {
var _this = this;
var beforeSaveEntity = (this.beforeSaveEntity || noopBeforeSaveEntity).bind(this);
var entityTypeMap = {};
var entityInfos = this.entitiesFromClient.map(function (entity) {
// transform entities from how they are sent from the client
// into entityInfo objects which is how they are exposed
// to interception on the server.
var entityAspect = entity.entityAspect;
var entityTypeName = entityAspect.entityTypeName;
var entityType = entityTypeMap[entityTypeName];
if (!entityType) {
entityType = _this.metadataStore.getEntityType(entityTypeName);
if (entityType) {
entityTypeMap[entityTypeName] = entityType;
}
else {
throw new Error("Unable to locate server side metadata for an EntityType named: " + entityTypeName);
}
}
var unmapped = entity.__unmapped;
var ei = { entity: entity, entityType: entityType, entityAspect: entityAspect, unmapped: unmapped };
// just to be sure that we don't try to send it to the db server or return it to the client.
delete entity.entityAspect;
return ei;
}, this);
// create the saveMap (entities to be saved) grouped by entityType
var saveMapData = _.groupBy(entityInfos, function (entityInfo) {
// _.groupBy will bundle all undefined returns together.
if (beforeSaveEntity(entityInfo)) {
return entityInfo.entityType.name;
}
});
// remove the entries where beforeSaveEntity returned false ( they are all grouped under 'undefined'
delete saveMapData["undefined"];
// want to have SaveMap functions available
var saveMap = _.extend(new SaveMap_1.SaveMap(this), saveMapData);
return this._saveWithTransaction(saveMap);
};
SequelizeSaveHandler.prototype._saveWithTransaction = function (saveMap) {
var _this = this;
var sequelize = this.sequelizeManager.sequelize;
return sequelize.transaction().then(function (trx) {
// this.transaction = trx;
var beforeSaveEntities = (_this.beforeSaveEntities || noopBeforeSaveEntities).bind(_this);
// beforeSaveEntities will either return nothing or a promise.
var nextPromise = bluebird_1.Promise.resolve(beforeSaveEntities(saveMap, trx));
// saveCore returns either a list of entities or an object with an errors property.
return nextPromise.then(function (sm) {
return _this._saveCore(saveMap, trx);
}).then(function (r) {
if (r.errors) {
trx.rollback();
return r;
}
else {
trx.commit();
return { entities: r, keyMappings: _this._keyMappings };
}
}).catch(function (e) {
trx.rollback();
throw e;
});
});
};
;
SequelizeSaveHandler.prototype._saveCore = function (saveMap, transaction) {
var _this = this;
if (saveMap.entityErrors || saveMap.errorMessage) {
return bluebird_1.Promise.resolve({ errors: saveMap.entityErrors || [], message: saveMap.errorMessage });
}
promise = this.keyGenerator.getNextId(keyProperties[0]).then(function(nextId) {
realKeyValue = nextId;
entity[firstKeyPropName] = realKeyValue;
var entityTypes = _.keys(saveMap).map(function (entityTypeName) {
// guaranteed to succeed because these have all been looked up earlier.
return _this.metadataStore.getEntityType(entityTypeName);
}, this);
var sortedEntityTypes = toposortEntityTypes(entityTypes);
var entityGroups = sortedEntityTypes.map(function (entityType) {
return { entityType: entityType, entityInfos: saveMap[entityType.name] };
});
} else if (autoGeneratedKeyType == "Identity") {
var keyDataTypeName = keyProperties[0].dataType.name;
if (keyDataTypeName === "Guid") {
// handled here instead of one the db server.
realKeyValue = createGuid();
entity[firstKeyPropName] = realKeyValue;
} else {
// realValue will be set during 'create' promise resolution below
realKeyValue = null;
// value will be set by server's autoincrement logic
delete entity[firstKeyPropName];
// do adds/updates first followed by deletes in reverse order.
// add/updates come first because we might move children off of a parent before deleting the parent
// and we don't want to cause a constraint exception by deleting the parent before all of its
// children have been moved somewhere else.
return bluebird_1.Promise.reduce(entityGroups, function (savedEntities, entityGroup) {
return _this._processEntityGroup(entityGroup, transaction, false).then(function (entities) {
Array.prototype.push.apply(savedEntities, entities);
return savedEntities;
});
}, []).then(function (entitiesHandledSoFar) {
return bluebird_1.Promise.reduce(entityGroups.reverse(), function (savedEntities, entityGroup) {
return _this._processEntityGroup(entityGroup, transaction, true).then(function (entities) {
Array.prototype.push.apply(savedEntities, entities);
return savedEntities;
});
}, entitiesHandledSoFar);
});
};
SequelizeSaveHandler.prototype._processEntityGroup = function (entityGroup, transaction, processDeleted) {
var _this = this;
var entityType = entityGroup.entityType;
var entityInfos = entityGroup.entityInfos.filter(function (entityInfo) {
var isDeleted = entityInfo.entityAspect.entityState == "Deleted";
return processDeleted ? isDeleted : !isDeleted;
});
var sqModel = this.sequelizeManager.entityTypeSqModelMap[entityType.name];
entityInfos = toposortEntityInfos(entityType, entityInfos);
if (processDeleted) {
entityInfos = entityInfos.reverse();
}
}
promise = promise || Promise.resolve(null);
promise = promise.then(function() {
// tempKeyValue will be undefined in entity was created on the server
if (tempKeyValue != undefined) {
keyMapping = { entityTypeName: entityTypeName, tempValue: tempKeyValue, realValue: realKeyValue };
return bluebird_1.Promise.reduce(entityInfos, function (savedEntities, entityInfo) {
// function returns a promise for this entity
// and updates the results array.
return _this._saveEntityAsync(entityInfo, sqModel, transaction).then(function (savedEntity) {
savedEntities.push(savedEntity);
return savedEntities;
});
}, []);
};
;
SequelizeSaveHandler.prototype._saveEntityAsync = function (entityInfo, sqModel, transaction) {
// function returns a promise for this entity
// and updates the results array.
var _this = this;
// not a "real" entityAspect - just the salient pieces sent from the client.
var entity = entityInfo.entity;
var entityAspect = entityInfo.entityAspect;
var entityType = entityInfo.entityType;
var entityTypeName = entityType.name;
// TODO: determine if this is needed because we need to strip the entityAspect off the entity for inserts.
entityAspect.entity = entity;
// TODO: we really only need to coerce every field on an insert
// only selected fields are needed for update and delete.
this._coerceData(entity, entityType);
var keyProperties = entityType.keyProperties;
var firstKeyPropName = keyProperties[0].nameOnServer;
var entityState = entityAspect.entityState;
var trxOptions = { transaction: transaction };
var promise;
if (entityState === "Added") {
var keyMapping_1 = null;
// NOTE: there are two instances of autoGeneratedKeyType available
// one on entityType which is part of the metadata and a second
// on the entityAspect that was sent as part of the save.
// The one on the entityAspect "overrides" the one on the entityType.
var autoGeneratedKey = entityAspect.autoGeneratedKey;
var autoGeneratedKeyType = autoGeneratedKey && autoGeneratedKey.autoGeneratedKeyType;
var tempKeyValue_1 = entity[firstKeyPropName];
if (autoGeneratedKeyType && autoGeneratedKeyType !== "None") {
var realKeyValue_1;
if (autoGeneratedKeyType == "KeyGenerator") {
if (this.keyGenerator == null) {
throw new Error("No KeyGenerator was provided for property:" + keyProperties[0].name + " on entityType: " + entityType.name);
}
promise = this.keyGenerator.getNextId(keyProperties[0]).then(function (nextId) {
realKeyValue_1 = nextId;
entity[firstKeyPropName] = realKeyValue_1;
});
}
else if (autoGeneratedKeyType == "Identity") {
var keyDataTypeName = keyProperties[0].dataType.name;
if (keyDataTypeName === "Guid") {
// handled here instead of one the db server.
realKeyValue_1 = createGuid();
entity[firstKeyPropName] = realKeyValue_1;
}
else {
// realValue will be set during 'create' promise resolution below
realKeyValue_1 = null;
// value will be set by server's autoincrement logic
delete entity[firstKeyPropName];
}
}
promise = promise || bluebird_1.Promise.resolve(null);
promise = promise.then(function () {
// tempKeyValue will be undefined in entity was created on the server
if (tempKeyValue_1 != undefined) {
keyMapping_1 = { entityTypeName: entityTypeName, tempValue: tempKeyValue_1, realValue: realKeyValue_1 };
}
});
}
promise = promise || bluebird_1.Promise.resolve(null);
return promise.then(function () {
return sqModel.create(entity, { transaction: transaction }).then(function (savedEntity) {
if (keyMapping_1) {
if (keyMapping_1.realValue === null) {
keyMapping_1.realValue = savedEntity[firstKeyPropName];
}
var tempKeyString = buildKeyString(entityType, tempKeyValue_1);
_this._fkFixupMap[tempKeyString] = keyMapping_1.realValue;
_this._keyMappings.push(keyMapping_1);
}
return _this._addToResults(savedEntity.dataValues, entityTypeName);
}).catch(handleItemSaveError(entity, entityState));
});
}
})
}
promise = promise || Promise.resolve(null);
return promise.then(function() {
return sqModel.create(entity, {transaction: transaction}).then(function(savedEntity) {
//return sqModel.create(entity).then(function(savedEntity) {
if (keyMapping) {
if (keyMapping.realValue === null) {
keyMapping.realValue = savedEntity[firstKeyPropName];
}
var tempKeyString = buildKeyString(entityType, tempKeyValue);
that._fkFixupMap[tempKeyString] = keyMapping.realValue;
that._keyMappings.push(keyMapping);
else if (entityState === "Modified") {
var whereHash_1 = {};
keyProperties.forEach(function (kp) {
whereHash_1[kp.nameOnServer] = entity[kp.nameOnServer];
});
if (entityType.concurrencyProperties && entityType.concurrencyProperties.length > 0) {
entityType.concurrencyProperties.forEach(function (cp) {
// this is consistent with the client behaviour where it does not update the version property
// if its data type is binary
if (cp.dataType.name === 'Binary')
whereHash_1[cp.nameOnServer] = entity[cp.nameOnServer];
else
whereHash_1[cp.nameOnServer] = entityAspect.originalValuesMap[cp.nameOnServer];
});
}
var setHash_1;
if (entityInfo.forceUpdate) {
setHash_1 = _.clone(entity);
// remove fields that we don't want to 'set'
delete setHash_1.entityAspect;
// TODO: should we also remove keyProps here...
}
else {
setHash_1 = {};
var ovm = entityAspect.originalValuesMap;
if (ovm == null) {
throw new Error("Unable to locate an originalValuesMap for one of the 'Modified' entities to be saved");
}
Object.keys(ovm).forEach(function (k) {
// if k is one of the entityKeys do no allow this
var isKeyPropName = keyProperties.some(function (kp) {
return kp.nameOnServer == k;
});
if (isKeyPropName) {
throw new Error("Breeze does not support updating any part of the entity's key insofar as this changes the identity of the entity");
}
setHash_1[k] = entity[k];
});
}
// don't bother executing update statement if nothing to update
// this can happen if setModified is called without any properties being changed.
if (_.isEmpty(setHash_1)) {
return bluebird_1.Promise.resolve(this._addToResults(entity, entityTypeName));
}
return sqModel.update(setHash_1, { where: whereHash_1, transaction: transaction }).then(function (infoArray) {
var itemsSaved = infoArray[0];
if (itemsSaved != 1) {
var err = new Error("unable to update entity - concurrency violation");
err.entity = entity;
err.entityState = entityState;
throw err;
}
// HACK: Sequelize 'update' does not return the entity; so
// we are just returning the original entity here.
return _this._addToResults(entity, entityTypeName);
}).catch(handleItemSaveError(entity, entityState));
}
return that._addToResults(savedEntity.dataValues, entityTypeName);
}).catch(handleItemSaveError(entity, entityState));
});
} else if (entityState === "Modified") {
var whereHash = {};
keyProperties.forEach(function (kp) {
whereHash[kp.nameOnServer] = entity[kp.nameOnServer];
});
if (entityType.concurrencyProperties && entityType.concurrencyProperties.length > 0) {
entityType.concurrencyProperties.forEach(function (cp) {
// this is consistent with the client behaviour where it does not update the version property
// if its data type is binary
if (cp.dataType.name === 'Binary')
whereHash[cp.nameOnServer] = entity[cp.nameOnServer];
else
whereHash[cp.nameOnServer] = entityAspect.originalValuesMap[cp.nameOnServer];
});
}
var setHash;
if (entityInfo.forceUpdate) {
setHash = _.clone(entity);
// remove fields that we don't want to 'set'
delete setHash.entityAspect;
// TODO: should we also remove keyProps here...
} else {
setHash = {};
var ovm = entityAspect.originalValuesMap;
if (ovm == null) {
throw new Error("Unable to locate an originalValuesMap for one of the 'Modified' entities to be saved");
}
Object.keys(ovm).forEach(function (k) {
// if k is one of the entityKeys do no allow this
var isKeyPropName = keyProperties.some(function(kp) {
return kp.nameOnServer == k;
else if (entityState = "Deleted") {
var whereHash_2 = {};
keyProperties.forEach(function (kp) {
whereHash_2[kp.nameOnServer] = entity[kp.nameOnServer];
});
// we don't bother with concurrency check on deletes
// TODO: we may want to add a 'switch' for this later.
return sqModel.destroy({ where: whereHash_2, limit: 1, transaction: transaction }).then(function () {
// Sequelize 'destroy' does not return the entity; so
// we are just returning the original entity here.
return _this._addToResults(entity, entityTypeName);
}).catch(handleItemSaveError(entity, entityState));
}
};
SequelizeSaveHandler.prototype._addToResults = function (entity, entityTypeName) {
entity.$type = entityTypeName;
this._savedEntities.push(entity);
return entity;
};
SequelizeSaveHandler.prototype._coerceData = function (entity, entityType) {
var _this = this;
entityType.dataProperties.forEach(function (dp) {
var val = entity[dp.nameOnServer];
if (val != null) {
if (dp.relatedNavigationProperty != null) {
// if this is an fk column and it has a value
// check if there is a fixed up value.
var key = buildKeyString(dp.relatedNavigationProperty.entityType, val);
var newVal = _this._fkFixupMap[key];
if (newVal) {
entity[dp.nameOnServer] = newVal;
}
}
var dtName = dp.dataType.name;
if (dtName === "DateTime" || dtName === "DateTimeOffset") {
entity[dp.nameOnServer] = new Date(Date.parse(val));
}
}
else {
// // this allows us to avoid inserting a null.
// // TODO: think about an option to allow this if someone really wants to.
// delete entity[dp.name];
// }
}
});
if (isKeyPropName) {
throw new Error("Breeze does not support updating any part of the entity's key insofar as this changes the identity of the entity");
}
setHash[k] = entity[k];
});
}
var that = this;
// don't bother executing update statement if nothing to update
// this can happen if setModified is called without any properties being changed.
if (_.isEmpty(setHash)) {
return Promise.resolve(that._addToResults(entity, entityTypeName));
}
return sqModel.update(setHash, { where: whereHash, transaction: transaction }).then(function(infoArray) {
//return sqModel.update(setHash, { where: whereHash }).then(function(infoArray) {
var itemsSaved = infoArray[0];
if (itemsSaved != 1) {
var err = new Error("unable to update entity - concurrency violation");
err.entity = entity;
err.entityState = entityState;
throw err;
}
// HACK: Sequelize 'update' does not return the entity; so
// we are just returning the original entity here.
return that._addToResults(entity, entityTypeName);
}).catch(handleItemSaveError(entity, entityState));
} else if (entityState = "Deleted") {
var whereHash = {};
keyProperties.forEach(function (kp) {
whereHash[kp.nameOnServer] = entity[kp.nameOnServer];
});
// we don't bother with concurrency check on deletes
// TODO: we may want to add a 'switch' for this later.
return sqModel.destroy({ where: whereHash, limit: 1, transaction: transaction}).then(function() {
//return sqModel.destroy({ where: whereHash, limit: 1}).then(function() {
// Sequelize 'destroy' does not return the entity; so
// we are just returning the original entity here.
return that._addToResults(entity, entityTypeName);
}).catch(handleItemSaveError(entity, entityState))
}
};
ctor.prototype._addToResults = function(entity, entityTypeName) {
entity.$type = entityTypeName;
this._savedEntities.push(entity);
return entity;
};
ctor.prototype._coerceData = function(entity, entityType) {
var that = this;
entityType.dataProperties.forEach(function(dp) {
var val = entity[dp.nameOnServer];
if (val != null) {
if (dp.relatedNavigationProperty != null) {
// if this is an fk column and it has a value
// check if there is a fixed up value.
var key = buildKeyString(dp.relatedNavigationProperty.entityType, val);
var newVal = that._fkFixupMap[key];
if (newVal) {
entity[dp.nameOnServer] = newVal;
}
}
var dtName = dp.dataType.name;
if (dtName === "DateTime" || dtName === "DateTimeOffset") {
entity[dp.nameOnServer] = new Date(Date.parse(val));
}
} else {
// // this allows us to avoid inserting a null.
// // TODO: think about an option to allow this if someone really wants to.
// delete entity[dp.name];
// }
}
})
};
return SequelizeSaveHandler;
}());
exports.SequelizeSaveHandler = SequelizeSaveHandler;
function noopBeforeSaveEntities(saveMap, trx) {
return saveMap;
}
function SaveMap(sequelizeSaveHandler) {
// want to make sequelizeSaveHandler non enumerable.
Object.defineProperty(this, "sequelizeSaveHandler", { value: sequelizeSaveHandler });
}
SaveMap.prototype.getEntityType = function(entityTypeName) {
return this.sequelizeSaveHandler.metadataStore.getEntityType(entityTypeName);
}
SaveMap.prototype.getEntityInfosOfType = function(entityTypeName) {
var entityType = this.getEntityType(entityTypeName);
// entityType.name is fully qualified.
return this[entityType.name] || [];
}
SaveMap.prototype.addEntity = function(entityTypeName, entity, entityState) {
var entityType = this.getEntityType(entityTypeName);
entityTypeName = entityType.name; // fully qualified now.
var entityInfo = {
entity: entity, entityType: entityType, wasAddedOnServer: true
};
entityInfo.entityAspect = {
entityTypeName: entityTypeName,
entityState: entityState || "Added"
}
var entityInfoList = this[entityTypeName];
if (entityInfoList) {
entityInfoList.push(entityInfo);
} else {
this[entityTypeName] = [ entityInfo ];
}
return entityInfo;
}
SaveMap.prototype.addEntityError = function(entityInfo, errorName, errorMessage, propertyName) {
if (!this.entityErrors) {
this.entityErrors = [];
}
var entityType = entityInfo.entityType;
var keyValues = entityType.keyProperties.map(function (kp) {
return entityInfo.entity[kp.nameOnServer];
});
this.entityErrors.push({
entityTypeName: entityType.name,
errorName: errorName,
errorMessage: errorMessage,
propertyName: propertyName,
keyValues: keyValues
});
}
SaveMap.prototype.setErrorMessage = function(errorMessage) {
this.errorMessage = errorMessage;
}
// will either return nothing or a promise.
function noopBeforeSaveEntities(saveMap) {
return
}
function noopBeforeSaveEntity(entityInfo) {
return true;
return true;
}
/** Sort the EntityTypes based on their dependencies */
function toposortEntityTypes(entityTypes) {
var edges = [];
entityTypes.forEach(function(et) {
et.foreignKeyProperties.forEach(function(fkp) {
if (fkp.relatedNavigationProperty) {
var dependsOnType = fkp.relatedNavigationProperty.entityType;
if (et != dependsOnType) {
edges.push( [et, dependsOnType]);
}
}
var edges = [];
entityTypes.forEach(function (et) {
et.foreignKeyProperties.forEach(function (fkp) {
if (fkp.relatedNavigationProperty) {
var dependsOnType = fkp.relatedNavigationProperty.entityType;
if (et != dependsOnType) {
edges.push([et, dependsOnType]);
}
}
});
});
});
// this should work but toposort.array seems to have a bug ...
// var sortedEntityTypes = toposort.array(entityTypes, edges).reverse();
// so use this instead.
var allSortedTypes = toposort(edges).reverse();
allSortedTypes.forEach(function(st, ix) {
st.index = ix;
});
var sortedEntityTypes = entityTypes.sort(function(a, b) {
return a.index - b.index;
});
return sortedEntityTypes;
// this should work but toposort.array seems to have a bug ...
// let sortedEntityTypes = toposort.array(entityTypes, edges).reverse();
// so use this instead.
var allSortedTypes = toposort(edges).reverse();
allSortedTypes.forEach(function (st, ix) {
st.index = ix;
});
var sortedEntityTypes = entityTypes.sort(function (a, b) {
return a.index - b.index;
});
return sortedEntityTypes;
}
/** Sort the EntityInfos of a given type based foreign key relationships */
function toposortEntityInfos(entityType, entityInfos) {
var edges = [];
var selfReferenceNavProp = _.find(entityType.navigationProperties, navProp => navProp.entityType === entityType);
if (!selfReferenceNavProp || !selfReferenceNavProp.relatedDataProperties)
return entityInfos;
var fkDataProp = selfReferenceNavProp.relatedDataProperties[0].name;
var keyProp = entityType.keyProperties[0].name;
entityInfos.forEach(function(entityInfo) {
var dependsOn = entityInfo.entity[fkDataProp];
if (dependsOn) {
var dependsOnInfo = _.find(entityInfos, x => x.entity[keyProp] === dependsOn && x.entity !== entityInfo.entity); // avoid referencing the same object
if (dependsOnInfo)
edges.push([entityInfo, dependsOnInfo]);
var edges = [];
var selfReferenceNavProp = _.find(entityType.navigationProperties, function (navProp) { return navProp.entityType === entityType; });
if (!selfReferenceNavProp || !selfReferenceNavProp.relatedDataProperties) {
return entityInfos;
}
});
if (edges.length === 0)
return entityInfos;
var allSortedEntityInfos = toposort(edges).reverse();
allSortedEntityInfos.forEach(function(st, ix) {
st.__index = ix;
});
var sortedEntityInfos = entityInfos.sort(function(a, b) {
return a.__index - b.__index;
});
return sortedEntityInfos;
var fkDataProp = selfReferenceNavProp.relatedDataProperties[0].name;
var keyProp = entityType.keyProperties[0].name;
entityInfos.forEach(function (entityInfo) {
var dependsOn = entityInfo.entity[fkDataProp];
if (dependsOn) {
var dependsOnInfo = _.find(entityInfos, function (x) { return x.entity[keyProp] === dependsOn && x.entity !== entityInfo.entity; }); // avoid referencing the same object
if (dependsOnInfo)
edges.push([entityInfo, dependsOnInfo]);
}
});
if (edges.length === 0) {
return entityInfos;
}
var allSortedEntityInfos = toposort(edges).reverse();
allSortedEntityInfos.forEach(function (st, ix) {
st.__index = ix;
});
var sortedEntityInfos = entityInfos.sort(function (a, b) {
return a.__index - b.__index;
});
return sortedEntityInfos;
}
function buildKeyString(entityType, val) {
return entityType.name + "::" + val.toString();
return entityType.name + "::" + val.toString();
}
function handleItemSaveError(entity, entityState) {
return function(err) {
err = typeof(err) == 'string' ? new Error(err) : err;
var detailedMsg = (err.name ? "error name: " + err.name : "") + ( err.sql ? " sql: " + err.sql : "");
err.message = err.message ? err.message + ". " + detailedMsg : detailedMsg;
err.entity = entity;
err.entityState = entityState;
throw err;
}
return function (err) {
err = typeof (err) == 'string' ? new Error(err) : err;
var detailedMsg = (err.name ? "error name: " + err.name : "") + (err.sql ? " sql: " + err.sql : "");
err.message = err.message ? err.message + ". " + detailedMsg : detailedMsg;
err.entity = entity;
err.entityState = entityState;
throw err;
};
}
function createGuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// Not needed.
//// task is a function that returns a promise.
//function sequencePromises(tasks) {
// var current = Promise.resolve(), results = [];
// for (var k = 0; k < tasks.length; ++k) {
// results.push(current = current.then(tasks[k]));
// }
// return Promise.all(results);
//}
//# sourceMappingURL=SequelizeSaveHandler.js.map

@@ -1,8 +0,14 @@

exports.log = log;
exports.log.enabled = true;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function log(s) {
if (!log.enabled) return;
console.log('[Breeze] ' + s + '\n');
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (!log['enabled'])
return;
console.log('[Breeze] ' + s + '\n', args);
}
exports.log = log;
log['enabled'] = true;
//# sourceMappingURL=utils.js.map
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc