mongo-portable
Version:
Portable Pure JS MongoDB - Based on Monglodb (https://github.com/euforic/monglodb.git) by Christian Sullivan (http://RogueSynaptics.com)
589 lines • 25 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
/***
* @file MongoPortable.js - based on Monglo ({@link https://github.com/Monglo}) by Christian Sullivan <cs@euforic.co> | Copyright (c) 2012
* @version 1.0.0
*
* @author Eduardo Astolfi <eastolfi91@gmail.com>
* @copyright 2016 Eduardo Astolfi <eastolfi91@gmail.com>
* @license MIT Licensed
*/
var jsw_logger_1 = require("jsw-logger");
var _ = require("lodash");
var Promise = require("promise");
var collection_1 = require("../collection");
var document_1 = require("../document");
var emitter_1 = require("../emitter");
var utils_1 = require("../utils");
/***
* MongoPortable
*
* @module MongoPortable
* @since 0.0.1
*
* @classdesc Portable database with persistence and MongoDB-like API
*
* @param {string} databaseName - Name of the database.
*/
var MongoPortable = /** @class */ (function (_super) {
__extends(MongoPortable, _super);
function MongoPortable(databaseName, options) {
var _this = _super.call(this, options || { log: {} }) || this;
_this.logger = jsw_logger_1.JSWLogger.instance;
// If we have already this instance, return it
if (MongoPortable._connHelper.hasConnection(databaseName)) {
return MongoPortable._connHelper.getConnection(databaseName).instance;
}
else {
_this._collections = {};
_this._stores = [];
// Check ddbb name format
MongoPortable._connHelper.validateDatabaseName(databaseName);
_this._databaseName = databaseName;
MongoPortable._connHelper.addConnection(databaseName, new document_1.ObjectId(), _this);
}
return _this;
}
MongoPortable.prototype.emit = function (name, args) {
return _super.prototype.emit.call(this, name, args, this._stores);
};
/***
* Middleware functions
*
* @param {String} name - Name of the middleware:
* <ul>
* <li>"store": Add a custom store</li>
* </ul>
* @param {Object|Function} fn - Function to implement the middleware
*/
MongoPortable.prototype.use = function (name, obj) {
switch (name) {
case "store":
this._stores.push(obj);
break;
}
};
/***
* Adds a custom stores for remote and local persistence
*
* @param {Object|Function} store - The custom store
*
* @returns {MongoPortable} this - The current Instance
*/
MongoPortable.prototype.addStore = function (store) {
if (_.isNil(store)) {
this.logger.throw("missing \"store\" parameter");
}
if (_.isFunction(store)) {
return this.addStoreFromFunction(store);
}
else if (_.isObject(store)) {
return this.addStoreFromObject(store);
}
else {
this.logger.throw("\"store\" must be a function or object");
}
return this;
};
MongoPortable.prototype.addStoreFromFunction = function (storeClass) {
var store = new storeClass();
return this.addStoreFromObject(store);
};
MongoPortable.prototype.addStoreFromObject = function (store) {
this._stores.push(store);
return this;
};
/***
* Returns a cursor to all the collection information.
*
* @param {String} [collectionName=null] - the collection name we wish to retrieve the information from.
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @returns {Array}
*
* @todo Implement
*/
MongoPortable.prototype.collectionsInfo = function (collectionName, callback) {
this.logger.throw("Not implemented yet");
};
/***
* Alias for {@link MongoPortable#collections}
*
* @method MongoPortable#fetchCollections
*/
MongoPortable.prototype.fetchCollections = function (options, callback) {
return this.collections(options, callback);
};
/***
* Get the list of all collection for the specified db
*
* @method MongoPortable#collections
*
* @param {Object} [options] - Additional options
*
* @param {Boolean} [options.namesOnly=false] - Return only the collections names
* @param {String|Array} [options.collectionName=null] - The collection name we wish to filter by
*
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @return {Array}
*/
MongoPortable.prototype.collections = function (options, callback) {
if (_.isNil(callback) && _.isFunction(options)) {
callback = options;
}
if (_.isNil(options)) {
options = {};
}
var self = this;
var collectionList = [];
for (var name_1 in self._collections) {
// Only add the requested collections //TODO Add array type
if (options.collectionName) {
if (name_1.toLowerCase() === options.collectionName.toLowerCase()) {
if (options.namesOnly) {
collectionList.push(name_1);
}
else {
collectionList.push(self._collections[name_1]);
}
}
}
else {
if (options.namesOnly) {
collectionList.push(name_1);
}
else {
collectionList.push(self._collections[name_1]);
}
}
}
if (callback) {
callback(collectionList);
}
return collectionList;
};
/***
* Get the list of all collection names for the specified db,
* by calling MongoPortable#collections with [options.namesOnly = true]
*
* @method MongoPortable#collectionNames
*
* @param {Object} [options] - Additional options.
*
* @param {String|Array} [options.collectionName=null] - The collection name we wish to filter by.
*
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @return {Array}
*
* {@link MongoPortable#collections}
*/
MongoPortable.prototype.collectionNames = function (options, callback) {
if (_.isNil(callback) && _.isFunction(options)) {
callback = options;
}
if (_.isNil(options)) {
options = {};
}
options.namesOnly = true;
return this.collections(options, callback);
};
/***
* Creates a collection on a server pre-allocating space, need to create f.ex capped collections.
*
* @method MongoPortable#collection
*
* @param {String} collectionName - the collection name we wish to access.
* @param {Object} [options] - returns option results.
*
* @param {Boolean|Object} [options.safe=false] Executes with a getLastError command returning the results of the command on MongoMonglo:
* <ul>
* <li>true</li>
* <li>false</li>
* <li>{ w: {Number}, wtimeout: {Number}}</li>
* <li>{ fsync: true }</li>
* </ul>
* @param {Boolean} [options.serializeFunctions=false] - Serialize functions on the document.
* @param {Boolean} [options.raw=false] - Perform all operations using raw bson objects.
* @param {Object} [options.pkFactory=null] - Object overriding the basic ObjectId primary key generation.
* @param {Boolean} [options.capped=false] - Create a capped collection.
* @param {Number} [options.size=4096] - The size of the capped collection in bytes.
* @param {Number} [options.max=500] - The maximum number of documents in the capped collection.
* @param {Boolean} [options.autoIndexId=false] - Create an index on the _id field of the document, not created automatically on capped collections.
* @param {String} [options.readPreference=ReadPreference.PRIMARY] - Te prefered read preference:
* <ul>
* <li>ReadPreference.PRIMARY</li>
* <li>ReadPreference.PRIMARY_PREFERRED</li>
* <li>ReadPreference.SECONDARY</li>
* <li>ReadPreference.SECONDARY_PREFERRED</li>
* <li>ReadPreference.NEAREST</li>
* </ul>
*
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @fires {@link MongoStore#createCollection}
*
* @returns {Promise<Collection>}
*/
MongoPortable.prototype.collection = function (collectionName, options, callback) {
var _this = this;
return new Promise(function (resolve, reject) {
var existing = true;
// var collection;
// var collectionFullName = self.databaseName + "." + collectionName;
if (_.isFunction(options)) {
callback = options;
options = {};
}
else {
options = options || {};
}
if (!_this._collections[collectionName]) {
_this._collections[collectionName] = new collection_1.Collection(_this, collectionName /*, this.pkFactory*/ /*, options*/);
existing = false;
}
/***
* "createCollection" event.
*
* @event MongoPortable~createCollection
*
* @property {Object} connection - Information about the current database connection
* @property {Object} collection - Information about the collection created
*/
_this.emit("createCollection", {
connection: _this,
collection: _this._collections[collectionName]
}).then(function () {
if (!existing) {
// Letting access the collection by <MongoPortable instance>.<COL_NAME>
Object.defineProperty(MongoPortable.prototype, collectionName, {
enumerable: true,
configurable: true,
writable: false,
value: _this._collections[collectionName]
});
}
// return self._collections[collectionName];
if (callback) {
callback(null, _this._collections[collectionName]);
}
resolve(_this._collections[collectionName]);
}).catch(function (error) {
if (callback) {
callback(error, null);
}
reject(error);
});
});
};
/***
* Alias for {@link MongoPortable#collection}
*
* @method MongoPortable#createCollection
*/
MongoPortable.prototype.createCollection = function (collectionName, options, callback) {
return this.collection(collectionName, options, callback);
};
/***
* Drop a collection from the database, removing it permanently. New accesses will create a new collection.
*
* @method MongoPortable#dropCollection
*
* @param {String} collectionName - The name of the collection we wish to drop.
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @returns {Promise<Boolean>} Promise with "true" if dropped successfully
*/
MongoPortable.prototype.dropCollection = function (collectionName, callback) {
var _this = this;
return new Promise(function (resolve, reject) {
if (_this._collections[collectionName]) {
// Drop the collection
_this.emit("dropCollection", {
conn: _this,
collection: _this._collections[collectionName]
}).then(function () {
delete _this._collections[collectionName];
if (callback && _.isFunction(callback)) {
callback(null, true);
}
resolve(true);
}).catch(function (error) {
if (callback && _.isFunction(callback)) {
callback(error, false);
}
reject(error);
});
}
else {
var error = new Error("No collection found");
_this.logger.throw(error);
if (callback && _.isFunction(callback)) {
callback(error, false);
}
reject(error);
}
});
};
/***
* Rename a collection.
*
* @method MongoPortable#renameCollection
*
* @param {String} fromCollection - The name of the current collection we wish to rename.
* @param {String} toCollection - The new name of the collection.
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @returns {Promise<Collection>} Promise with the renamed collection
*/
MongoPortable.prototype.renameCollection = function (fromCollection, toCollection, callback) {
var _this = this;
return new Promise(function (resolve, reject) {
if (!_.isString(fromCollection) || !_.isString(toCollection) || fromCollection === toCollection) {
var error = new Error("You should pass two different string names");
_this.logger.throw(error);
if (callback && _.isFunction(callback)) {
callback(error, null);
}
reject(error);
}
else {
collection_1.Collection.checkCollectionName(toCollection);
if (_this._collections[fromCollection]) {
_this.emit("renameCollection", {
conn: _this,
from: fromCollection,
to: toCollection
}).then(function () {
var renamed = _this._collections[fromCollection].rename(toCollection);
if (renamed) {
utils_1.Utils.renameObjectProperty(_this._collections, fromCollection, toCollection);
// this._collections.renameProperty(fromCollection, toCollection);
// this.renameProperty(fromCollection, toCollection);
utils_1.Utils.renameObjectProperty(_this, fromCollection, toCollection);
if (callback && _.isFunction(callback)) {
callback(null, renamed);
}
resolve(renamed);
}
else {
reject(new Error("Could not rename collection"));
}
}).catch(function (error) {
_this.logger.throw(error);
if (callback && _.isFunction(callback)) {
callback(error, null);
}
reject(error);
});
}
else {
var error = new Error("No collection found");
_this.logger.throw(error);
if (callback && _.isFunction(callback)) {
callback(error, null);
}
reject(error);
}
}
});
};
/***
* Creates an index on the collection.
*
* @method MongoPortable#createIndex
*
* @param {String} collectionName - Name of the collection to create the index on.
* @param {Object} fieldOrSpec - FieldOrSpec that defines the index.
* @param {Object} [options] - Additional options during update.
*
* @param {Boolean|Object} [options.safe=false] Executes with a getLastError command returning the results of the command on MongoMonglo:
* <ul>
* <li>true</li>
* <li>false</li>
* <li>{ w: {Number}, wtimeout: {Number}}</li>
* <li>{ fsync: true }</li>
* </ul>
* @param {Boolean} [options.unique=false] - Creates an unique index
* @param {Boolean} [options.sparse=false] - Creates a sparse index
* @param {Boolean} [options.background=false] - Creates the index in the background, yielding whenever possible
* @param {Boolean} [options.dropDups=false] - A unique index cannot be created on a key that has pre-existing duplicate values.
* If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
* @param {Number} [options.min=null] - For geospatial indexes set the lower bound for the co-ordinates
* @param {Number} [options.max=null] - For geospatial indexes set the high bound for the co-ordinates
* @param {Number} [options.v=null] - Specify the format version of the indexes
* @param {Number} [options.expireAfterSeconds=null] - Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
* @param {String} [options.name=null] - Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
*
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @todo Implement
*/
MongoPortable.prototype.createIndex = function (collectionName, fieldOrSpec, options, callback) {
this.logger.throw("Not implemented yet!");
};
/***
* Ensures that an index exists, if it does not it creates it
*
* @method MongoPortable#ensureIndex
*
* @param {String} collectionName - Name of the collection to create the index on.
* @param {Object} fieldOrSpec - FieldOrSpec that defines the index.
* @param {Object} [options] - Additional options during update.
*
* @param {Boolean|Object} [options.safe=false] - Executes with a getLastError command returning the results of the command on MongoMonglo:
* <ul>
* <li>true</li>
* <li>false</li>
* <li>{ w: {Number}, wtimeout: {Number}}</li>
* <li>{ fsync: true }</li>
* </ul>
* @param {Boolean} [options.unique=false] - Creates an unique index
* @param {Boolean} [options.sparse=false] - Creates a sparse index
* @param {Boolean} [options.background=false] - Creates the index in the background, yielding whenever possible
* @param {Boolean} [options.dropDups=false] - A unique index cannot be created on a key that has pre-existing duplicate values.
* If you would like to create the index anyway, keeping the first document the database indexes and deleting all subsequent documents that have duplicate value
* @param {Number} [options.min] - For geospatial indexes set the lower bound for the co-ordinates
* @param {Number} [options.max] - For geospatial indexes set the high bound for the co-ordinates
* @param {Number} [options.v] - Specify the format version of the indexes
* @param {Number} [options.expireAfterSeconds] - Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
* @param {String} [options.name] - Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
*
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @todo Implement
*/
MongoPortable.prototype.ensureIndex = function (collectionName, fieldOrSpec, options, callback) {
this.logger.throw("Not implemented yet!");
};
/***
* Drop an index on a collection.
*
* @method MongoPortable#dropIndex
*
* @param {String} collectionName - The name of the collection where the command will drop an index.
* @param {String} indexName - Name of the index to drop.
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @todo Implement
*/
MongoPortable.prototype.dropIndex = function (collectionName, indexName, callback) {
this.logger.throw("Not implemented yet!");
};
/***
* Reindex all indexes on the collection
* Warning: "reIndex" is a blocking operation (indexes are rebuilt in the foreground) and will be slow for large collections.
*
* @method MongoPortable#reIndex
*
* @param {String} collectionName - The name of the collection to reindex
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @todo Implement
**/
MongoPortable.prototype.reIndex = function (collectionName, callback) {
this.logger.throw("Not implemented yet!");
};
/***
* Retrieves this collections index info.
*
* @method MongoPortable#indexInformation
*
* @param {String} collectionName - The name of the collection.
* @param {Object} [options] Additional options during update.
*
* @param {Boolean} [full=false] - Returns the full raw index information.
* @param {String} [readPreference] - The preferred read preference ((Server.PRIMARY, Server.PRIMARY_PREFERRED, Server.SECONDARY, Server.SECONDARY_PREFERRED, Server.NEAREST).
*
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @todo Implement
*/
MongoPortable.prototype.indexInformation = function (collectionName, options, callback) {
this.logger.throw("Not implemented yet!");
};
/***
* Drop the whole database.
*
* @method MongoPortable#dropDatabase
*
* @param {Function} [callback=null] - Callback function to be called at the end with the results
*
* @return {Promise<Boolean>} Promise with "true" if dropped successfully
*/
MongoPortable.prototype.dropDatabase = function (callback) {
var _this = this;
return new Promise(function (resolve, reject) {
if (MongoPortable._connHelper.hasConnection(_this._databaseName)) {
_this.emit("dropDatabase", {
conn: _this
}).then(function () {
MongoPortable._connHelper.dropConnection(_this._databaseName);
_this._collections = [];
_this._stores = [];
if (callback && _.isFunction(callback)) {
callback(null, true);
}
resolve(true);
});
}
else {
var error = new Error("That database no longer exists");
_this.logger.throw(error);
if (callback && _.isFunction(callback)) {
callback(error, false);
}
reject(error);
}
});
};
/***
* Dereference a dbref, against a db
*
* @param {DBRef} dbRef db reference object we wish to resolve.
* @param {Function} [callback=null] Callback function to be called at the end with the results
*
* @todo Implement
*
* @ignore
*/
MongoPortable.prototype.dereference = function (dbRef, callback) {
// TODO
// var db = this;
// // If we have a db reference then let"s get the db first
// if (dbRef.db !== null) db = this.db(dbRef.db);
// // Fetch the collection and find the reference
// var collection = Monglo.collection(dbRef.namespace);
// collection.findOne({"_id":dbRef.oid}, function(err, result) {
// callback(err, result);
// });
};
/***
* Retrieves the instance of that DDBB name
*
* @param {String} name - The DDBB name
*
* @return {MongoPortable} - The DDBB instance
*/
MongoPortable.getInstance = function (name) {
if (!_.isNil(name)) {
return MongoPortable._connHelper.getConnection(name);
}
return null;
};
MongoPortable._connHelper = new utils_1.ConnectionHelper();
return MongoPortable;
}(emitter_1.EventEmitter));
exports.MongoPortable = MongoPortable;
//# sourceMappingURL=MongoPortable.js.map