vulcain-corejs
Version:
Vulcain micro-service framework
375 lines (373 loc) • 19.5 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
const annotations_1 = require("./../../di/annotations");
const requestContext_1 = require("./../../servers/requestContext");
const mongodb_1 = require("mongodb");
const annotations_2 = require("../../di/annotations");
const applicationRequestError_1 = require("../../errors/applicationRequestError");
const system_1 = require("../../configurations/globals/system");
/**
* Default mongo provider
*/
let MongoProvider = class MongoProvider {
constructor(_logger, ctx, uri, options) {
this._logger = _logger;
this.ctx = ctx;
this.options = options;
this.options = this.options || { authSource: "admin" };
// Try to fix topology was destroy error
/* this.options.socketOptions = this.options.socketOptions || {
noDelay: true,
connectTimeoutMS: 0,
socketTimeoutMS: 0
};*/
if (!uri) {
throw new Error("Uri is required for mongodb provider.");
}
this.state = { uri: uri, keyPropertyNameBySchemas: new Map() };
}
get address() {
return this.state.uri;
}
initializeTenantAsync(context, tenant) {
if (!tenant)
throw new Error("tenant is required");
// Insert tenant in connexion string
let url = this.state.uri;
let parts = url.split('?');
if (parts[0][parts[0].length - 1] === "/")
parts[0] += tenant;
else
parts[0] += "/" + tenant;
url = parts.join('?');
this.state.uri = url;
this.ctx.logVerbose(`MONGODB: Creating provider ${system_1.System.removePasswordFromUrl(this.state.uri)} for tenant ${tenant}`);
const state = this.state;
const options = this.options;
return new Promise((resolve, reject) => {
// Don't use 'this' here to avoid memory leaks
// Open connexion
mongodb_1.MongoClient.connect(state.uri, options, (err, db) => {
if (err) {
reject(err);
system_1.System.log.error(this.ctx, err, `MONGODB: Error when opening database ${system_1.System.removePasswordFromUrl(this.state.uri)} for tenant ${tenant}`);
return;
}
state._mongo = db;
resolve(() => {
db.close();
state._mongo = null;
state.dispose = null;
});
});
});
}
ensureSchemaReadyAsync(schema) {
let keyPropertyName = this.state.keyPropertyNameBySchemas.get(schema.name);
if (keyPropertyName) {
return Promise.resolve();
}
keyPropertyName = schema.getIdProperty() || "_id";
this.state.keyPropertyNameBySchemas.set(schema.name, keyPropertyName);
let keys;
for (let p in schema.description.properties) {
if (!schema.description.properties.hasOwnProperty(p))
continue;
let prop = schema.description.properties[p];
if (prop.unique) {
if (!keys)
keys = {};
keys[p] = prop.unique === true ? 1 : prop.unique;
}
}
if (!keys) {
return Promise.resolve();
}
const db = this.state._mongo;
return new Promise((resolve, reject) => {
// Don't use 'this' here to avoid memory leaks
// Open connexion
let indexName = schema.description.storageName + "_uniqueIndex";
db.createIndex(schema.description.storageName, keys, { w: 1, background: true, name: indexName, unique: true }, (err) => {
if (err) {
system_1.System.log.error(this.ctx, err, `MONGODB: Error when creating index for ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name}`);
}
else {
system_1.System.log.info(this.ctx, `MONGODB: Unique index created for ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name}`);
}
resolve();
});
});
}
/**
* Return a list of entities
* @param options
* @returns {Promise}
*/
getAllAsync(schema, options) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureSchemaReadyAsync(schema);
let page = options.page || 0;
let maxByPage = options.maxByPage || 100;
let query = options.query ? options.query.filter || options.query : {};
this.ctx.logVerbose(`MONGODB: Get all query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query: ${JSON.stringify(query)}`);
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
let db = this.state._mongo;
let cursor = db.collection(schema.description.storageName).find(query)
.skip(page * maxByPage)
.limit(maxByPage);
cursor.toArray((err, res) => {
if (err) {
this.ctx.logError(err, `MONGODB ERROR: Get all query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query: ${JSON.stringify(query)}`);
reject(err);
}
else {
this.ctx.logVerbose(`MONGODB: Get all query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query: ${JSON.stringify(query)} returns ${(res && res.length) || 0} values.`);
resolve(res);
}
});
}
catch (err) {
this.ctx.logError(err, `MONGODB ERROR: Get all query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query: ${JSON.stringify(query)}`);
reject(err);
}
}));
});
}
findOneAsync(schema, query) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureSchemaReadyAsync(schema);
this.ctx.logVerbose(`MONGODB: Get findone on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query : ${JSON.stringify(query)}`);
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
let db = this.state._mongo;
db.collection(schema.description.storageName).findOne(query, (err, res) => {
if (err) {
this.ctx.logError(err, `MONGODB: Get findone on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query : ${JSON.stringify(query)}`);
reject(err);
}
else {
this.ctx.logVerbose(`MONGODB: Get findone on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query : ${JSON.stringify(query)} returns ${(res && res.length) || 0} values.`);
resolve(res);
}
});
}
catch (err) {
this.ctx.logError(err, `MONGODB: Get findone on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with query : ${JSON.stringify(query)}`);
reject(err);
}
}));
});
}
/**
* Read an entity
* @param name
* @returns {Promise}
*/
getAsync(schema, name) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureSchemaReadyAsync(schema);
let filter = {};
filter[this.state.keyPropertyNameBySchemas.get(schema.name) || "_id"] = name;
this.ctx.logVerbose(`MONGODB: Get query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with filter : ${JSON.stringify(filter)}`);
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
let db = this.state._mongo;
db.collection(schema.description.storageName).findOne(filter, (err, res) => {
if (err) {
this.ctx.logError(err, `MONGODB ERROR: Get query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${name}`);
reject(this.normalizeErrors(name, err));
}
else {
this.ctx.logVerbose(`MONGODB: Get query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${name} returns a value: ${res !== null}`);
resolve(res);
}
});
}
catch (err) {
this.ctx.logError(err, `MONGODB ERROR: Get query on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${name}`);
reject(err);
}
}));
});
}
/**
* Delete an entity
* @param id
* @returns {Promise}
*/
deleteAsync(schema, old) {
return __awaiter(this, void 0, void 0, function* () {
if (!old)
throw new Error("MONGODB delete: Argument is required");
yield this.ensureSchemaReadyAsync(schema);
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
let id;
let keyPropertyName = this.state.keyPropertyNameBySchemas.get(schema.name);
if (typeof old === "string")
id = old;
else
id = old[keyPropertyName];
if (!id)
throw new Error(`MONGODB delete : Id must not be null`);
let filter = {};
filter[keyPropertyName || "_id"] = id;
try {
this.ctx.logVerbose(`MONGODB: Deleting entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with filter: ${JSON.stringify(filter)}`);
let db = this.state._mongo;
db.collection(schema.description.storageName).remove(filter, (err, res) => {
if (err) {
let e = this.normalizeErrors(id, err);
this.ctx.logError(e, `MONGODB ERROR : Deleting entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with filter: ${JSON.stringify(filter)}`);
reject(e);
}
else {
this.ctx.logVerbose(`MONGODB: Deleting entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with filter: ${JSON.stringify(filter)}. Result=${res}`);
resolve();
}
});
}
catch (err) {
this.ctx.logError(err, `MONGODB ERROR : Deleting entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with filter: ${JSON.stringify(filter)}`);
reject(err);
}
}));
});
}
normalizeErrors(id, err) {
if (!err || !err.errors)
return err;
let error = new applicationRequestError_1.ApplicationRequestError("Mongo error - " + (err.message || ""), []);
if (err.errors) {
for (let e in err.errors) {
if (!err.errors.hasOwnProperty(e))
continue;
let error = err.errors[e];
error.errors.push({ message: error.message, property: error.path, id: id });
}
}
return error;
}
/**
* Persist an entity
* @param entity
* @returns {Promise}
*/
createAsync(schema, entity) {
return __awaiter(this, void 0, void 0, function* () {
if (!entity)
throw new Error("MONGODB create: Entity is required");
yield this.ensureSchemaReadyAsync(schema);
entity._created = new Date().toUTCString();
let keyPropertyName = this.state.keyPropertyNameBySchemas.get(schema.name);
let id = entity[keyPropertyName];
if (!id)
throw new Error(`MONGODB create : ${keyPropertyName} must not be null`);
this.ctx.logVerbose(`MONGODB: Creating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}`);
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
let db = this.state._mongo;
db.collection(schema.description.storageName).insertOne(entity, (err) => {
if (err) {
let e = this.normalizeErrors(entity[keyPropertyName], err);
this.ctx.logError(e, `MONGODB ERROR : Creating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}`);
reject(e);
}
else {
this.ctx.logVerbose(`MONGODB: Creating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}. Success=true`);
resolve(entity);
}
});
}
catch (err) {
this.ctx.logError(err, `MONGODB ERROR : Creating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}`);
reject(err);
}
}));
});
}
/**
* Update an entity
* @param entity
* @param old
* @returns {Promise<T>}
*/
updateAsync(schema, entity, old) {
return __awaiter(this, void 0, void 0, function* () {
if (!entity)
throw new Error("Entity is required");
yield this.ensureSchemaReadyAsync(schema);
let keyPropertyName = this.state.keyPropertyNameBySchemas.get(schema.name);
let id = (old || entity)[keyPropertyName];
let filter = {};
filter[keyPropertyName || "_id"] = id;
this.ctx.logVerbose(`MONGODB: Updating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}`);
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
try {
let db = this.state._mongo;
let collection = db.collection(schema.description.storageName);
collection.findOne(filter, (err, initial) => {
if (err) {
let e = this.normalizeErrors(id, err);
this.ctx.logError(e, `MONGODB ERROR : Updating entity (check if exists) on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}`);
reject(e);
return;
}
if (!initial) {
err = new Error(`Can not update unknow entity ${id}, schema: ${schema.name}`);
this.ctx.logError(err, `MONGODB ERROR : Error when updating entity ${id}, schema: ${schema.name}`);
reject(err);
return;
}
let _id = initial._id;
initial = schema.deepAssign(initial, entity);
initial._updated = new Date().toUTCString();
initial._id = _id;
collection.updateOne(filter, initial, err => {
if (err) {
let e = this.normalizeErrors(id, err);
this.ctx.logError(e, `MONGODB ERROR : Updating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}`);
reject(e);
}
else {
this.ctx.logVerbose(`MONGODB: Updating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}. Success`);
resolve(initial);
}
});
});
}
catch (err) {
this.ctx.logError(err, `MONGODB ERROR : Updating entity on ${system_1.System.removePasswordFromUrl(this.state.uri)} for schema ${schema.name} with id: ${id}`);
reject(err);
}
}));
});
}
};
MongoProvider = __decorate([
__param(0, annotations_2.Inject(annotations_1.DefaultServiceNames.Logger)),
__param(1, annotations_2.Inject(annotations_1.DefaultServiceNames.RequestContext, true)),
__metadata("design:paramtypes", [Object, requestContext_1.RequestContext, String, Object])
], MongoProvider);
exports.MongoProvider = MongoProvider;
//# sourceMappingURL=provider.js.map