Socket
Socket
Sign inDemoInstall

breeze-sequelize

Package Overview
Dependencies
24
Maintainers
5
Versions
18
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.5.2 to 0.5.3

76

dbUtils.js
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const sequelize_1 = require("sequelize");
let utils = require('./utils.js');
let log = utils.log;
exports.connect = connect;
exports.createDb = createDb;
const utils_1 = require("./utils");
/** Connect to existing database.
* @returns Promise<"success"> or throws an error */
function connect(dbConfig, sequelizeOptions) {
let sequelize = new sequelize_1.Sequelize(dbConfig.dbName, dbConfig.user, dbConfig.password, sequelizeOptions);
let 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;
return __awaiter(this, void 0, void 0, function* () {
let sequelize = new sequelize_1.Sequelize(dbConfig.dbName, dbConfig.user, dbConfig.password, sequelizeOptions);
let statement = 'SELECT 1';
try {
const results = yield sequelize.query(statement, { type: sequelize_1.QueryTypes.RAW });
utils_1.log("Connected to database: " + dbConfig.dbName);
return "success";
}
catch (err) {
utils_1.log("Database error: " + dbConfig.dbName + " error: " + err.message);
throw err;
}
});
}
exports.connect = connect;
;
/** Create new database.
* @returns Promise<void> or throws an error */
function createDb(dbConfig, sequelizeOptions) {
let sequelize = new sequelize_1.Sequelize(null, dbConfig.user, dbConfig.password, sequelizeOptions);
let statement = 'CREATE DATABASE ' + dbConfig.dbName;
return sequelize.query(statement, { type: sequelize_1.QueryTypes.RAW }).then(() => {
log("Database created: " + dbConfig.dbName);
}).error(err => {
if (err.message && err.message.indexOf("ER_DB_CREATE_EXISTS") >= 0) {
log("Database already exists: " + dbConfig.dbName);
return __awaiter(this, void 0, void 0, function* () {
let sequelize = new sequelize_1.Sequelize(null, dbConfig.user, dbConfig.password, sequelizeOptions);
let statement = 'CREATE DATABASE ' + dbConfig.dbName;
try {
yield sequelize.query(statement, { type: sequelize_1.QueryTypes.RAW });
utils_1.log("Database created: " + dbConfig.dbName);
}
else {
log("Database creation error: " + dbConfig.dbName + " error: " + err.message);
throw err;
catch (err) {
if (err.message && err.message.indexOf("ER_DB_CREATE_EXISTS") >= 0) {
utils_1.log("Database already exists: " + dbConfig.dbName);
}
else {
utils_1.log("Database creation error: " + dbConfig.dbName + " error: " + err.message);
throw err;
}
}

@@ -41,19 +54,2 @@ });

exports.createDb = createDb;
;
// old version using node 'next' semantics.
// next => function(err, connection);
//function createDb(dbConfig, next ) {
// connect(dbConfig, function(err, connection) {
// if (err) return next(err);
//
// connection.query('CREATE DATABASE ' + dbConfig.dbName, function(err, results) {
// if (err && err.code != "ER_DB_CREATE_EXISTS") {
// log("Database creation error: " + err.message);
// next(err);
// }
// log("database created OR already exists.");
// next(null, connection);
// });
// });
//}
//# sourceMappingURL=dbUtils.js.map

@@ -12,6 +12,4 @@ "use strict";

exports.SaveMap = SaveMap_1.SaveMap;
const utils = require("./utils");
exports.utils = utils;
const dbUtils = require("./dbUtils");
exports.dbUtils = dbUtils;
const dbUtils_1 = require("./dbUtils");
exports.connect = dbUtils_1.connect;
const breeze_client_1 = require("breeze-client");

@@ -18,0 +16,0 @@ exports.breeze = breeze_client_1.breeze;

@@ -8,3 +8,2 @@ "use strict";

let log = utils.log;
;
// TODO: still need to handle inherited entity types - TPT

@@ -116,3 +115,3 @@ /** Maps Breeze metadata to Sequelize Models */

attributes.type = sqModel;
if (dataProperty.dataType == breeze_client_1.breeze.DataType.String && dataProperty.maxLength) {
if (dataProperty.dataType === breeze_client_1.breeze.DataType.String && dataProperty.maxLength) {
attributes.type = sequelize_1.DataTypes.STRING(dataProperty.maxLength);

@@ -125,5 +124,5 @@ }

attributes.primaryKey = true;
if (dataProperty.parentType.autoGeneratedKeyType == breeze_client_1.breeze.AutoGeneratedKeyType.Identity) {
if (dataProperty.parentType.autoGeneratedKeyType === breeze_client_1.breeze.AutoGeneratedKeyType.Identity) {
let dt = attributes.type;
if (dt.key == "INTEGER" || dt.key == "BIGINT") {
if (dt.key === "INTEGER" || dt.key === "BIGINT") {
attributes.autoIncrement = true;

@@ -130,0 +129,0 @@ }

{
"name": "breeze-sequelize",
"version": "0.5.2",
"version": "0.5.3",
"description": "Breeze Sequelize server implementation",

@@ -25,4 +25,3 @@ "keywords": [

"peerDependencies": {
"bluebird": "^3.7.2",
"breeze-client": ">=2.0.4",
"breeze-client": ">=2.0.7",
"lodash": "^4.17.15",

@@ -32,14 +31,13 @@ "sequelize": "^5.21.3"

"devDependencies": {
"@types/bluebird": "^3.5.29",
"@types/lodash": "^4.14.137",
"@types/node": "^12.12.26",
"@types/validator": "^12.0.1",
"breeze-client": "^2.0.7",
"chai": "^4.2.0",
"lodash": "^4.17.15",
"mocha": "^6.2.0",
"rimraf": "^3.0.1",
"typescript": "^3.7.5",
"bluebird": "^3.7.2",
"breeze-client": ">=2.0.4",
"lodash": "^4.17.15",
"sequelize": "^5.21.3"
"sequelize": "^5.21.3",
"tslint": "^6.0.0",
"typescript": "^3.7.5"
},

@@ -51,3 +49,3 @@ "scripts": {

"build": "tsc && npm pack && npm run install-to-demo",
"install-to-demo": "cd ../test/BreezeExpressDemo && npm install ../../src/breeze-sequelize-0.5.2.tgz",
"install-to-demo": "cd ../test/BreezeExpressDemo && npm install ../../src/breeze-sequelize-0.5.3.tgz",
"clean": "rimraf *.js && rimraf *.map && rimraf types"

@@ -54,0 +52,0 @@ },

@@ -43,5 +43,3 @@ "use strict";

const entityType = entityInfo.entityType;
const keyValues = entityType.keyProperties.map(kp => {
return entityInfo.entity[kp.nameOnServer];
});
const keyValues = entityType.keyProperties.map(kp => entityInfo.entity[kp.nameOnServer]);
this.entityErrors.push({

@@ -48,0 +46,0 @@ entityTypeName: entityType.name,

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -31,8 +40,12 @@ const sequelize_1 = require("sequelize");

authenticate() {
// check database connection
return this.sequelize.authenticate().then(() => {
log('Connection has been established successfully.');
}).error(err => {
log('Unable to connect to the database:', err);
throw err;
return __awaiter(this, void 0, void 0, function* () {
// check database connection
try {
yield this.sequelize.authenticate();
log('Connection has been established successfully.');
}
catch (err) {
log('Unable to connect to the database:', err);
throw err;
}
});

@@ -54,20 +67,22 @@ }

sync(shouldCreateDb, sequelizeOpts) {
if (shouldCreateDb) {
return this.createDb().then(() => {
return this.syncCore(this.sequelize, sequelizeOpts);
});
}
else {
return this.syncCore(this.sequelize, sequelizeOpts);
}
return __awaiter(this, void 0, void 0, function* () {
if (shouldCreateDb) {
yield this.createDb();
}
return yield this.syncCore(this.sequelize, sequelizeOpts);
});
}
syncCore(sequelize, sequelizeOpts) {
let defaultOptions = { force: true };
sequelizeOpts = _.extend(defaultOptions, sequelizeOpts || {});
return sequelize.sync(sequelizeOpts).then(() => {
log("schema created");
return sequelize;
}).catch(err => {
console.log("schema creation failed");
throw err;
return __awaiter(this, void 0, void 0, function* () {
let defaultOptions = { force: true };
sequelizeOpts = _.extend(defaultOptions, sequelizeOpts || {});
try {
return yield sequelize.sync(sequelizeOpts);
log("schema created");
return sequelize;
}
catch (err) {
console.log("schema creation failed");
throw err;
}
});

@@ -74,0 +89,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const breeze_client_1 = require("breeze-client");
const sequelize_1 = require("sequelize");
const SQVisitor_1 = require("./SQVisitor");
const _ = require("lodash");
const sequelize_1 = require("sequelize");
const urlUtils = require("url");
const SQVisitor_1 = require("./SQVisitor");
/** Create an EntityQuery from a JSON-format breeze query string

@@ -52,5 +61,6 @@ * @param url - url containing query, e.g. `/orders?{freight:{">":100}}`

execute(options) {
return this.executeRaw(options).then(r => {
return __awaiter(this, void 0, void 0, function* () {
const r = yield this.executeRaw(options);
let result = this._reshapeResults(r);
return Promise.resolve(result);
return result;
});

@@ -60,33 +70,27 @@ }

executeRaw(options) {
let self = this;
let model = self.sequelizeManager.resourceNameSqModelMap[self.entityQuery.resourceName];
let methodName = self.entityQuery.inlineCountEnabled ? "findAndCountAll" : "findAll";
options = options || { useTransaction: false, beforeQueryEntities: undefined };
return (function () {
if (options.useTransaction)
return self.sequelizeManager.sequelize.transaction()
.then(function (trans) {
self.transaction = trans;
self.sqQuery.transaction = trans;
});
else
return Promise.resolve();
})()
.then(function () {
if (options.beforeQueryEntities)
return options.beforeQueryEntities.call(self);
else
return Promise.resolve();
})
.then(function () {
return model[methodName].call(model, self.sqQuery);
})
.then(function (results) {
if (options.useTransaction)
self.sqQuery.transaction.commit();
return results;
}, function (e) {
if (options.useTransaction)
self.sqQuery.transaction.rollback();
throw e;
return __awaiter(this, void 0, void 0, function* () {
let model = this.sequelizeManager.resourceNameSqModelMap[this.entityQuery.resourceName];
let methodName = this.entityQuery.inlineCountEnabled ? "findAndCountAll" : "findAll";
options = options || { useTransaction: false, beforeQueryEntities: undefined };
if (options.useTransaction) {
const trans = yield this.sequelizeManager.sequelize.transaction();
this.transaction = trans;
this.sqQuery.transaction = trans;
}
if (options.beforeQueryEntities) {
return options.beforeQueryEntities.call(this);
}
try {
const results = yield model[methodName].call(model, this.sqQuery);
if (options.useTransaction) {
this.sqQuery.transaction.commit();
}
return results;
}
catch (e) {
if (options.useTransaction) {
this.sqQuery.transaction.rollback();
}
throw e;
}
});

@@ -224,3 +228,3 @@ }

// needed because we had to turn take(0) into limit(1)
if (this.entityQuery.takeCount == 0) {
if (this.entityQuery.takeCount === 0) {
sqResults = [];

@@ -328,3 +332,3 @@ }

}
if (expandProps == null || expandProps.length == 0)
if (expandProps == null || expandProps.length === 0)
return;

@@ -342,5 +346,3 @@ // now blow out all of the expands

return this._createResult(nextSqr, nextEntityType, true);
}, this).filter(r => {
return r != null;
});
}, this).filter(r => r != null);
}

@@ -397,3 +399,3 @@ else {

include.attributes = include.attributes || [];
if (include.attributes.length == 0) {
if (include.attributes.length === 0) {
include.attributes = include.model.primaryKeyAttributes;

@@ -440,5 +442,5 @@ }

function getKey(sqResult, entityType) {
let key = entityType.keyProperties.map(function (kp) {
return sqResult[kp.nameOnServer];
}).join("::") + "^" + entityType.name;
let key = entityType.keyProperties
.map(kp => sqResult[kp.nameOnServer])
.join("::") + "^" + entityType.name;
return key;

@@ -453,5 +455,3 @@ }

}
parent.include && parent.include.forEach(function (inc) {
processAndOr(inc);
});
parent.include && parent.include.forEach(inc => processAndOr(inc));
console.trace(parent);

@@ -464,5 +464,3 @@ }

if (ands) {
let clauses = ands.map(function (clause) {
return processAndOrClause(clause);
});
let clauses = ands.map(clause => processAndOrClause(clause));
return sequelize_1.Sequelize.and.apply(null, clauses);

@@ -472,5 +470,3 @@ // return Sequelize.and(clauses[0], clauses[1]);

else if (ors) {
let clauses = ors.map(function (clause) {
return processAndOrClause(clause);
});
let clauses = ors.map(clause => processAndOrClause(clause));
return sequelize_1.Sequelize.or.apply(null, clauses);

@@ -477,0 +473,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const bluebird_1 = require("bluebird");
// import Promise from 'bluebird';
const breeze_client_1 = require("breeze-client");
const _ = require("lodash");
const SaveMap_1 = require("./SaveMap");
let toposort = require("toposort");
class ServerSaveError extends Error {
constructor(m, entityErrors) {
super(m);
this.entityErrors = entityErrors;
// Set the prototype explicitly.
Object.setPrototypeOf(this, ServerSaveError.prototype);
}
}
exports.ServerSaveError = ServerSaveError;
class SequelizeSaveError extends Error {
constructor(e, entity, entityState) {
super(e.message);
e.stack = undefined;
breeze_client_1.core.extend(this, e);
this.entity = entity;
this.entityState = entityState;
Object.setPrototypeOf(this, SequelizeSaveError.prototype);
}
}
exports.SequelizeSaveError = SequelizeSaveError;
/** Handles saving entities from Breeze SaveChanges requests */

@@ -23,170 +53,172 @@ class SequelizeSaveHandler {

save() {
let beforeSaveEntity = (this.beforeSaveEntity || noopBeforeSaveEntity).bind(this);
let entityTypeMap = {};
let entityInfos = this.entitiesFromClient.map(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.
let entityAspect = entity.entityAspect;
let entityTypeName = entityAspect.entityTypeName;
let entityType = entityTypeMap[entityTypeName];
if (!entityType) {
entityType = this.metadataStore.getEntityType(entityTypeName);
if (entityType) {
entityTypeMap[entityTypeName] = entityType;
return __awaiter(this, void 0, void 0, function* () {
let beforeSaveEntity = (this.beforeSaveEntity || noopBeforeSaveEntity).bind(this);
let entityTypeMap = {};
let entityInfos = this.entitiesFromClient.map(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.
let entityAspect = entity.entityAspect;
let entityTypeName = entityAspect.entityTypeName;
let 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);
}
}
else {
throw new Error("Unable to locate server side metadata for an EntityType named: " + entityTypeName);
let unmapped = entity.__unmapped;
let 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;
});
// create the saveMap (entities to be saved) grouped by entityType
let saveMapData = _.groupBy(entityInfos, entityInfo => {
// _.groupBy will bundle all undefined returns together.
if (beforeSaveEntity(entityInfo)) {
return entityInfo.entityType.name;
}
}
let unmapped = entity.__unmapped;
let 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
let saveMapData = _.groupBy(entityInfos, 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
let saveMap = _.extend(new SaveMap_1.SaveMap(this), saveMapData);
return this._saveWithTransaction(saveMap);
});
// remove the entries where beforeSaveEntity returned false ( they are all grouped under 'undefined'
delete saveMapData["undefined"];
// want to have SaveMap functions available
let saveMap = _.extend(new SaveMap_1.SaveMap(this), saveMapData);
return this._saveWithTransaction(saveMap);
}
_saveWithTransaction(saveMap) {
let sequelize = this.sequelizeManager.sequelize;
return sequelize.transaction().then(trx => {
// this.transaction = trx;
return __awaiter(this, void 0, void 0, function* () {
let sequelize = this.sequelizeManager.sequelize;
// TODO: consider making the isolation level settable on the SequelizeManager.
// const trx = await sequelize.transaction( { isolationLevel: Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED });
const trx = yield sequelize.transaction();
let beforeSaveEntities = (this.beforeSaveEntities || noopBeforeSaveEntities).bind(this);
// beforeSaveEntities will either return nothing or a promise.
let nextPromise = bluebird_1.Promise.resolve(beforeSaveEntities(saveMap, trx));
const sm = yield beforeSaveEntities(saveMap, trx);
// saveCore returns either a list of entities or an object with an errors property.
return nextPromise.then(sm => {
return this._saveCore(saveMap, trx);
}).then((r) => {
if (r.errors) {
trx.rollback();
return r;
try {
const r = yield this._saveCore(saveMap, trx);
trx.commit();
return { entities: r, keyMappings: this._keyMappings };
}
catch (e) {
// will throw either a ServerSaveError or a SequelizeSaveError
trx.rollback();
// we have to return an object with an 'errors' property
if (e instanceof ServerSaveError) {
return { errors: e.entityErrors, message: e.message };
}
else if (e instanceof SequelizeSaveError) {
return { errors: [e], message: e.name + ": " + e.message };
}
else {
trx.commit();
return { entities: r, keyMappings: this._keyMappings };
return { errors: [], message: e.message };
}
}).catch((e) => {
trx.rollback();
throw e;
});
}
});
}
;
_saveCore(saveMap, transaction) {
if (saveMap.entityErrors || saveMap.errorMessage) {
return bluebird_1.Promise.resolve({ errors: saveMap.entityErrors || [], message: saveMap.errorMessage });
}
let entityTypes = _.keys(saveMap).map((entityTypeName) => {
return __awaiter(this, void 0, void 0, function* () {
if (saveMap.entityErrors || saveMap.errorMessage) {
throw new ServerSaveError(saveMap.errorMessage, saveMap.entityErrors);
}
// guaranteed to succeed because these have all been looked up earlier.
return this.metadataStore.getEntityType(entityTypeName);
}, this);
let sortedEntityTypes = toposortEntityTypes(entityTypes);
let entityGroups = sortedEntityTypes.map((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 bluebird_1.Promise.reduce(entityGroups, (savedEntities, entityGroup) => {
return this._processEntityGroup(entityGroup, transaction, false).then(entities => {
Array.prototype.push.apply(savedEntities, entities);
return savedEntities;
let entityTypes = _.keys(saveMap).map(entityTypeName => this.metadataStore.getEntityType(entityTypeName));
let sortedEntityTypes = toposortEntityTypes(entityTypes);
let entityGroups = sortedEntityTypes.map((entityType) => {
return { entityType: entityType, entityInfos: saveMap[entityType.name] };
});
}, []).then(entitiesHandledSoFar => {
return bluebird_1.Promise.reduce(entityGroups.reverse(), (savedEntities, entityGroup) => {
return this._processEntityGroup(entityGroup, transaction, true).then(entities => {
Array.prototype.push.apply(savedEntities, entities);
return savedEntities;
});
}, entitiesHandledSoFar);
// 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.
const addedUpdatedEntities = [];
// can't use entityGroups.map here because we DO NOT want the groups to run in parallel.
for (let entityGroup of entityGroups) {
const r = yield this._processEntityGroup(entityGroup, transaction, false);
addedUpdatedEntities.push(...r);
}
const deletedEntities = [];
// can't use entityGroups.map here because we DO NOT want the groups to run in parallel.
for (let entityGroup of entityGroups.reverse()) {
const r = yield this._processEntityGroup(entityGroup, transaction, true);
deletedEntities.push(...r);
}
const savedEntities = [...addedUpdatedEntities, ...deletedEntities];
return savedEntities;
});
}
_processEntityGroup(entityGroup, transaction, processDeleted) {
let entityType = entityGroup.entityType;
let entityInfos = entityGroup.entityInfos.filter(entityInfo => {
let isDeleted = entityInfo.entityAspect.entityState == "Deleted";
return processDeleted ? isDeleted : !isDeleted;
return __awaiter(this, void 0, void 0, function* () {
let entityType = entityGroup.entityType;
let entityInfos = entityGroup.entityInfos.filter(entityInfo => {
let isDeleted = entityInfo.entityAspect.entityState === "Deleted";
return processDeleted ? isDeleted : !isDeleted;
});
let sqModel = this.sequelizeManager.entityTypeSqModelMap[entityType.name];
entityInfos = toposortEntityInfos(entityType, entityInfos);
if (processDeleted) {
entityInfos = entityInfos.reverse();
}
const promises = entityInfos.map((entityInfo) => __awaiter(this, void 0, void 0, function* () {
return yield this._saveEntityAsync(entityInfo, sqModel, transaction);
}));
const savedEntities = yield Promise.all(promises);
return savedEntities;
});
let sqModel = this.sequelizeManager.entityTypeSqModelMap[entityType.name];
entityInfos = toposortEntityInfos(entityType, entityInfos);
if (processDeleted) {
entityInfos = entityInfos.reverse();
}
return bluebird_1.Promise.reduce(entityInfos, (savedEntities, entityInfo) => {
}
_saveEntityAsync(entityInfo, sqModel, transaction) {
return __awaiter(this, void 0, void 0, function* () {
// function returns a promise for this entity
// and updates the results array.
return this._saveEntityAsync(entityInfo, sqModel, transaction).then(savedEntity => {
savedEntities.push(savedEntity);
return savedEntities;
});
}, []);
}
;
_saveEntityAsync(entityInfo, sqModel, transaction) {
// function returns a promise for this entity
// and updates the results array.
// not a "real" entityAspect - just the salient pieces sent from the client.
let entity = entityInfo.entity;
let entityAspect = entityInfo.entityAspect;
let entityType = entityInfo.entityType;
let 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);
let keyProperties = entityType.keyProperties;
let firstKeyPropName = keyProperties[0].nameOnServer;
let entityState = entityAspect.entityState;
let trxOptions = { transaction: transaction };
let promise;
if (entityState === "Added") {
let 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.
let autoGeneratedKey = entityAspect.autoGeneratedKey;
let autoGeneratedKeyType = autoGeneratedKey && autoGeneratedKey.autoGeneratedKeyType;
let tempKeyValue = entity[firstKeyPropName];
if (autoGeneratedKeyType && autoGeneratedKeyType !== "None") {
let realKeyValue;
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((nextId) => {
// not a "real" entityAspect - just the salient pieces sent from the client.
let entity = entityInfo.entity;
let entityAspect = entityInfo.entityAspect;
let entityType = entityInfo.entityType;
let 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);
let keyProperties = entityType.keyProperties;
let firstKeyPropName = keyProperties[0].nameOnServer;
let entityState = entityAspect.entityState;
if (entityState === "Added") {
let 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.
let autoGeneratedKey = entityAspect.autoGeneratedKey;
let autoGeneratedKeyType = autoGeneratedKey && autoGeneratedKey.autoGeneratedKeyType;
let tempKeyValue = entity[firstKeyPropName];
if (autoGeneratedKeyType && autoGeneratedKeyType !== "None") {
let realKeyValue;
if (autoGeneratedKeyType === "KeyGenerator") {
if (this.keyGenerator == null) {
throw new Error("No KeyGenerator was provided for property:" + keyProperties[0].name + " on entityType: " + entityType.name);
}
const nextId = yield this.keyGenerator.getNextId(keyProperties[0]);
realKeyValue = nextId;
entity[firstKeyPropName] = realKeyValue;
});
}
else if (autoGeneratedKeyType == "Identity") {
let 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];
else if (autoGeneratedKeyType === "Identity") {
let 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];
}
}
}
promise = promise || bluebird_1.Promise.resolve(null);
promise = promise.then(() => {
// tempKeyValue will be undefined in entity was created on the server

@@ -196,7 +228,5 @@ if (tempKeyValue != undefined) {

}
});
}
promise = promise || bluebird_1.Promise.resolve(null);
return promise.then(() => {
return sqModel.create(entity, { transaction: transaction }).then((savedEntity) => {
}
try {
const savedEntity = yield sqModel.create(entity, { transaction: transaction });
if (keyMapping) {

@@ -211,75 +241,86 @@ if (keyMapping.realValue === null) {

return this._addToResults(savedEntity.dataValues, entityTypeName);
}).catch(handleItemSaveError(entity, entityState));
});
}
else if (entityState === "Modified") {
let whereHash = {};
keyProperties.forEach(kp => {
whereHash[kp.nameOnServer] = entity[kp.nameOnServer];
});
if (entityType.concurrencyProperties && entityType.concurrencyProperties.length > 0) {
entityType.concurrencyProperties.forEach(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];
}
catch (e) {
throw new SequelizeSaveError(e, entity, entityState);
}
}
else if (entityState === "Modified") {
let whereHash = {};
keyProperties.forEach(kp => {
whereHash[kp.nameOnServer] = entity[kp.nameOnServer];
});
}
let 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 = {};
let ovm = entityAspect.originalValuesMap;
if (ovm == null) {
throw new Error("Unable to locate an originalValuesMap for one of the 'Modified' entities to be saved");
if (entityType.concurrencyProperties && entityType.concurrencyProperties.length > 0) {
entityType.concurrencyProperties.forEach(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];
});
}
Object.keys(ovm).forEach(k => {
// if k is one of the entityKeys do no allow this
let isKeyPropName = keyProperties.some(kp => {
return kp.nameOnServer == k;
let 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 = {};
let 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(k => {
// if k is one of the entityKeys do no allow this
let isKeyPropName = keyProperties.some(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[k] = entity[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");
}
// 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 this._addToResults(entity, entityTypeName);
}
try {
const infoArray = yield sqModel.update(setHash, { where: whereHash, transaction: transaction });
let itemsSaved = infoArray[0];
if (itemsSaved !== 1) {
let err = new Error("unable to update entity - concurrency violation");
err.entity = entity;
err.entityState = entityState;
throw err;
}
setHash[k] = entity[k];
// HACK: Sequelize 'update' does not return the entity; so
// we are just returning the original entity here.
return this._addToResults(entity, entityTypeName);
}
catch (e) {
throw new SequelizeSaveError(e, entity, entityState);
}
}
else if (entityState === "Deleted") {
let whereHash = {};
keyProperties.forEach(kp => {
whereHash[kp.nameOnServer] = entity[kp.nameOnServer];
});
try {
// we don't bother with concurrency check on deletes
// TODO: we may want to add a 'switch' for this later.
yield sqModel.destroy({ where: whereHash, limit: 1, transaction: transaction });
// Sequelize 'destroy' does not return the entity; so
// we are just returning the original entity here.
return this._addToResults(entity, entityTypeName);
}
catch (e) {
throw new SequelizeSaveError(e, entity, entityState);
}
}
// 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 bluebird_1.Promise.resolve(this._addToResults(entity, entityTypeName));
}
return sqModel.update(setHash, { where: whereHash, transaction: transaction }).then(infoArray => {
let itemsSaved = infoArray[0];
if (itemsSaved != 1) {
let 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));
}
else if (entityState === "Deleted") {
let whereHash = {};
keyProperties.forEach(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(() => {
// 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));
}
});
}

@@ -333,3 +374,3 @@ _addToResults(entity, entityTypeName) {

let dependsOnType = fkp.relatedNavigationProperty.entityType;
if (et != dependsOnType) {
if (et !== dependsOnType) {
edges.push([et, dependsOnType]);

@@ -384,14 +425,5 @@ }

}
function handleItemSaveError(entity, entityState) {
return function (err) {
err = typeof (err) == 'string' ? new Error(err) : err;
let 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) {
// tslint:disable-next-line: triple-equals
let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);

@@ -398,0 +430,0 @@ return v.toString(16);

@@ -31,3 +31,3 @@ "use strict";

}
else if (this.expr1.visitorMethodName == "fnExpr") {
else if (this.expr1.visitorMethodName === "fnExpr") {
p1Value = processFnExpr(this.expr1, context, result);

@@ -47,3 +47,3 @@ }

}
else if (op == "startswith") {
else if (op === "startswith") {
crit = { [like]: p2Value + "%" };

@@ -63,3 +63,3 @@ }

}
else if (this.expr2.visitorMethodName == "propExpr") {
else if (this.expr2.visitorMethodName === "propExpr") {
let p2Value = this.expr2.propertyPath;

@@ -112,6 +112,6 @@ let props = context.entityType.getPropertiesOnPath(p2Value, context.toNameOnServer, true);

let includes = [];
if (predSqs.length == 0) {
if (predSqs.length === 0) {
return null;
}
else if (predSqs.length == 1) {
else if (predSqs.length === 1) {
return predSqs[0];

@@ -135,3 +135,3 @@ }

else {
if (include.where == null) {
if (include.where === null) {
include.where = sourceInclude.where;

@@ -144,3 +144,3 @@ }

}
if (include.attributes == null || include.attributes.length == 0) {
if (include.attributes === null || include.attributes.length === 0) {
include.attributes = sourceInclude.attributes;

@@ -162,3 +162,3 @@ }

if (wheres.length > 0) {
result.where = wheres.length == 1 ? wheres[0] : { [sequelize_1.Op.and]: wheres };
result.where = wheres.length === 1 ? wheres[0] : { [sequelize_1.Op.and]: wheres };
}

@@ -168,7 +168,7 @@ // q = Sequelize.and(q1, q2);

else {
if (includes.length > 1 || (includes.length == 1 && wheres.length != 0)) {
if (includes.length > 1 || (includes.length === 1 && wheres.length !== 0)) {
throw new Error("Cannot translate a query with nested property paths and 'OR' conditions to Sequelize. (Sorry).");
}
if (wheres.length > 0) {
result.where = wheres.length == 1 ? wheres[0] : { [sequelize_1.Op.or]: wheres };
result.where = wheres.length === 1 ? wheres[0] : { [sequelize_1.Op.or]: wheres };
}

@@ -207,3 +207,3 @@ // q = Sequelize.or(q1, q2);

let where;
if (typeof (p1Value) == 'string') {
if (typeof (p1Value) === 'string') {
where = {};

@@ -256,3 +256,3 @@ where[p1Value] = crit;

}
else if (expr.visitorMethodName == 'fnExpr') {
else if (expr.visitorMethodName === 'fnExpr') {
let exprVal = processFnExpr(expr, context, result);

@@ -306,6 +306,6 @@ return exprVal;

let errMsg;
if (exprs.length != 1) {
if (exprs.length !== 1) {
errMsg = formatString(errTmpl + " This function only takes a single parameter", fnName);
}
else if (exprs[0].visitorMethodName == 'litExpr') {
else if (exprs[0].visitorMethodName === 'litExpr') {
errMsg = formatString(errTmpl + " The single parameter may not be a literal expression. Param: %2", fnName, exprs[0].toString());

@@ -319,6 +319,6 @@ }

// format("a %1 and a %2", "cat", "dog") -> "a cat and a dog"
function formatString(string, ...rest) {
function formatString(str, ...rest) {
let args = arguments;
let pattern = RegExp("%([1-" + (arguments.length - 1) + "])", "g");
return string.replace(pattern, function (match, index) {
return str.replace(pattern, function (match, index) {
return args[index];

@@ -325,0 +325,0 @@ });

import { SequelizeQuery, SequelizeQueryResult, urlToEntityQuery } from "./SequelizeQuery";
import { SequelizeManager, KeyGenerator } from "./SequelizeManager";
import { SequelizeSaveHandler, SequelizeSaveResult, ServerEntityInfo, ServerEntityAspect, ServerEntity, ServerEntityState } from "./SequelizeSaveHandler";
import { SequelizeSaveHandler, ServerSaveResult, ServerEntityInfo, ServerEntityAspect, ServerEntity, ServerEntityState } from "./SequelizeSaveHandler";
import { SaveMap } from './SaveMap';
import * as utils from "./utils";
import * as dbUtils from "./dbUtils";
import { connect } from "./dbUtils";
import { breeze } from "breeze-client";
declare const Sequelize: typeof import("sequelize/types").Sequelize;
export { Sequelize, SequelizeQuery, SequelizeManager, SequelizeSaveHandler, KeyGenerator, SequelizeQueryResult, SequelizeSaveResult, SaveMap, ServerEntity, ServerEntityAspect, ServerEntityInfo, ServerEntityState, urlToEntityQuery, utils, dbUtils, breeze };
export { Sequelize, SequelizeQuery, SequelizeManager, SequelizeSaveHandler, KeyGenerator, SequelizeQueryResult, ServerSaveResult as SequelizeSaveResult, SaveMap, ServerEntity, ServerEntityAspect, ServerEntityInfo, ServerEntityState, urlToEntityQuery, connect, breeze };

@@ -31,4 +31,4 @@ import { Sequelize, Options, SyncOptions } from "sequelize";

/** Sync the Sequelize model with the database */
sync(shouldCreateDb: boolean, sequelizeOpts: SyncOptions): Promise<Sequelize>;
sync(shouldCreateDb: boolean, sequelizeOpts: SyncOptions): Promise<any>;
private syncCore;
}

@@ -1,4 +0,4 @@

import { Entity, EntityType, KeyMapping, MetadataStore, SaveOptions } from "breeze-client";
import { EntityType, KeyMapping, MetadataStore, SaveOptions } from "breeze-client";
import { BaseError, Transaction } from "sequelize";
import { SaveMap } from "./SaveMap";
import { Transaction } from "sequelize";
import { KeyGenerator, SequelizeManager } from "./SequelizeManager";

@@ -16,6 +16,2 @@ export declare type OpenObj = {

}
export interface ServerEntity {
[k: string]: any;
entityAspect: ServerEntityAspect;
}
/** Server-side representation of entity that came from the client */

@@ -30,2 +26,6 @@ export interface ServerEntityInfo {

}
export interface ServerEntity {
[k: string]: any;
entityAspect: ServerEntityAspect;
}
export interface ServerEntityAspect {

@@ -44,2 +44,21 @@ entityTypeName: string;

}
export declare type ServerSaveResult = ServerGoodSaveResult | ServerBadSaveResult;
export interface ServerGoodSaveResult {
entities: OpenObj[];
keyMappings: KeyMapping[];
}
export interface ServerBadSaveResult {
errors: any[];
message: string;
[k: string]: any;
}
export declare class ServerSaveError extends Error {
entityErrors: ServerEntityError[];
constructor(m: string, entityErrors?: ServerEntityError[]);
}
export declare class SequelizeSaveError extends Error {
entity: OpenObj;
entityState: ServerEntityState;
constructor(e: BaseError, entity: OpenObj, entityState?: ServerEntityState);
}
/** Validation error created on the server */

@@ -53,10 +72,2 @@ export interface ServerEntityError {

}
export interface SequelizeSaveError {
errors: ServerEntityError[];
message: string;
}
export interface SequelizeSaveResult {
entities: Entity[];
keyMappings: KeyMapping[];
}
export declare type BeforeSaveEntityFn = (e: ServerEntityInfo) => boolean;

@@ -82,3 +93,3 @@ export declare type BeforeSaveEntitiesFn = (sm: SaveMap, trx?: Transaction) => Promise<SaveMap>;

/** Save the entities in the save request, returning either the saved entities or an error collection */
save(): Promise<SequelizeSaveResult>;
save(): Promise<ServerSaveResult>;
private _saveWithTransaction;

@@ -85,0 +96,0 @@ private _saveCore;

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