UNPKG

vulcain-corejs

Version:
375 lines (373 loc) 19.5 kB
"use strict"; 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