Hummingbird: Adapter
Manages connection to data store

@constructor
512751
function() {
  this._waterline = new Waterline();
  
  // Adapters
  this._adapters = {
    memory: require('./adapters/memory.js'),
    disk:   require('./adapters/disk.js'),
    redis:  require('./adapters/redis.js')
  };
  
  // Models
  this._models = {
    account: Waterline.Collection.extend(require('./models/account.js')),
    keyword: Waterline.Collection.extend(require('./models/keyword.js'))
  };
}
1200621
async function getConnection(url, opts = {}) {
    try {
        const dbName = opts.databaseName;
        if (!dbName || dbName === '')
            throw boom.badImplementation('jollof-data-arangodb: databaseName config is required', { url, opts })

        const key = url + dbName;

        //Get connection
        let connection;
        if (connPool[key]) {
            connection = connPool[key];
        } else {
            connection = new Database(opts)
            connection.useBasicAuth(opts.username, opts.password)
            connPool[key] = connection;
        }

        //Now ensure database exists
        const dbNames = await connection.listDatabases();
        if (dbNames.indexOf(dbName) > -1) {
            //our db exists. use it.
            connection.useDatabase(dbName)
        } else {
            //our db does not exist. Attempting to create it
            await connection.createDatabase(dbName)
            connection.useDatabase(dbName)
        }

        return connection;
    } catch (e) {
        console.error(`There was an issue creating/ensuring connection to DB: ${url} with opts: ${util.inspect(opts)}`)
        throw new Error(e);
    }
}
1358277
function (callback) {
            debug('');

            self.eventStore.on('connect', function () {
              self.emit('connect');
            });

            self.eventStore.on('disconnect', function () {
              self.emit('disconnect');
            });

            self.eventStore.init(callback);
          }
989147
function CanaryStore() {
  var self = this;
  EventEmitter.call(self);
  var counter = self._counter = new Counter();
  counter.on('resource', self._onresource.bind(self));

  self._id = 0;
  self._variants = {};
  self._callbacks = {};
  self._assigners = [];
  self._assignments = {};
  self._overrides = {};
  self._pending = 0;

  // create a global context for simple cases
  var context = this._globalContext = this.context(this.emit.bind(this, 'change'));
  this.get = context.get.bind(context);
  this.start = context.start.bind(context);
  this.stop = context.stop.bind(context);
}
722169
function(object, object_id) {
    var res = {
      client_id:     this._credentials.client_id,
      client_secret: this._credentials.client_secret,
      object:        object,
      aspect:        'media',
      verify_token:  'hummingbird',
      callback_url:  this._callback
    };
    if (object_id) res.object_id = object_id;
    return res;
  }
1325618
function connectToDB(connObject, ssl, _callback) {
        let connection;
        let sslObject;
        let connectionObject;
        if (ssl == true) {
            sslObject = {
                ca: fs.readFileSync(connObject.certificatePath),
            };
        }
        console.log('Setting connection params');
        if (connObject.dbtype === 'mysql') {
            if (ssl == true) {
                connectionObject = {
                    host: connObject.server,
                    port: connObject.port,
                    user: connObject.username,
                    password: connObject.password,
                    database: connObject.database,
                    connectTimeout: connObject.connTimeout,
                    ssl: sslObject,
                };
            } else {
                connectionObject = {
                    host: connObject.server,
                    port: connObject.port,
                    user: connObject.username,
                    password: connObject.password,
                    database: connObject.database,
                    connectTimeout: connObject.timeout,
                };
            }

            console.log('After initializing params for connection');
            // check if db connection string is provided
            if (checkTypes.assigned(connObject.connectionString)) {
                connection = mysql.createConnection(connectString);
            } else {
                connection = mysql.createConnection(connectionObject);
            }
            console.log('Calling connection connect');
            connection.connect(function(err) {
                _callback(err, connection);
                return connection;
            });
            return connection;
        } else {
            // TBD: Add implementation for handling other types of database and drivers.
            console.log('Invalid Database Type');
            return 0;
        }
    }
137600
function() {
        if (!this._disconnected) {
            console.log(
                `LocalIndexedDBStoreBackend.connect: already connected or connecting`,
            );
            return Promise.resolve();
        }

        this._disconnected = false;

        console.log(
            `LocalIndexedDBStoreBackend.connect: connecting...`,
        );
        const req = this.indexedDB.open(this._dbName, VERSION);
        req.onupgradeneeded = (ev) => {
            const db = ev.target.result;
            const oldVersion = ev.oldVersion;
            console.log(
                `LocalIndexedDBStoreBackend.connect: upgrading from ${oldVersion}`,
            );
            if (oldVersion < 1) { // The database did not previously exist.
                this._isNewlyCreated = true;
                createDatabase(db);
            }
            if (oldVersion < 2) {
                upgradeSchemaV2(db);
            }
            if (oldVersion < 3) {
                upgradeSchemaV3(db);
            }
            // Expand as needed.
        };

        req.onblocked = () => {
            console.log(
                `can't yet open LocalIndexedDBStoreBackend because it is open elsewhere`,
            );
        };

        console.log(
            `LocalIndexedDBStoreBackend.connect: awaiting connection...`,
        );
        return reqAsEventPromise(req).then((ev) => {
            console.log(
                `LocalIndexedDBStoreBackend.connect: connected`,
            );
            this.db = ev.target.result;

            // add a poorly-named listener for when deleteDatabase is called
            // so we can close our db connections.
            this.db.onversionchange = () => {
                this.db.close();
            };

            return this._init();
        });
    }
1198483
function handleDisconnect() {
    _connection = _mysql.createConnection(_dbConfig);

    _connection.connect(function (err) {
        if (err) {
            console.log('error when connecting to db:', err);
            setTimeout(handleDisconnect, 2000);
        }
    });

    _connection.on('error', function (err) {
        console.log('db error', err);
        if (err.code === 'PROTOCOL_CONNECTION_LOST') {
            handleDisconnect();
        } else {
            throw err;
        }
    });
}
819222
function execute(req, res) {

  // if we have a sparse db store we need
  // to ensure a database exists
  if(!this.store.databases[req.args[0]]) {
    this.store.getDatabase(req.args[0], {pattern: this.pattern});
  }

  // update the connection with their selected db index
  req.conn.db = req.args[0];

  res.send(null, Constants.OK);
}
310867
function ReconnectingConnection(id, connection) {
  this.id = id;
  this.connection = null;
  this.closed = false;
  this.queue = [];

  this.setConnection(connection);
}
14685
function middlewareStrategy(metadata, dataAdapter, opts) {
    opts.filter = opts.filter || defaultFilter;
    const { filter } = opts;
    return async function magic(ctx, next) {
        const { name, key } = opts.filter.call(null, ctx);
        const obj = metadata[name];
        const { routeSwitch = {} } = obj;

        let middleware;
        if (routeSwitch[key] === true) {
            const { pres, posts } = getHooks(obj, key);
            const route = routes[key];
            middleware = route.call(null, name, dataAdapter, opts, pres, posts);
        }

        try {
            if (typeof middleware === 'function') {
                await middleware.call(null, ctx, next);
            } else {
                await next();
            }
        } catch (err) {
            throw err;
        }
    }
}
455615
function connectApp(token) {
  const CONNECTION = new Connection();

  return new Promise((resolve, reject) => {
    CONNECTION.connect(token)
      .then(() => resolve(new ConnectionHandler(CONNECTION)))
      .catch((error) => reject(error));
  });
}
357278
function Server(/* [options], [connectionListener] */) {
    events.EventEmitter.call(this);
    var self = this;

    var options;
    if (typeof arguments[0] === 'function') {
        options = {};
        this.on('connection', arguments[0]);
    } else {
        options = arguments[0] || {};
        if (typeof arguments[1] === 'function') {
            this.on('connection', arguments[1]);
        }
    }

    this._server = net.createServer(options, this._handler.bind(this));
    this._server.on('listening', function () {
        self.emit('listening');
    })
    this._server.on('close', function () {
        self.emit('close');
    })
    this._server.on('error', function (e) {
        self.emit('error', e);
    });
}
854297
function getDatabaseConnector(database, options, callback) {
    if (typeof options === "function") {
        callback = options
        options = {}
    }

    options = extend({}, defaults, options)

    var server = new Server(options.host, options.port, options.serverOptions)
        , databaseConnector = new Db(database, server, options.dbOptions)

    databaseConnector.open(authOrReturn)

    function authOrReturn(err, db) {
        if (err) {
            return callback(err)
        }

        if (options.user || options.password) {
            db.authenticate(options.user, options.password
                , options.authenticateOptions, returnDb)
        } else {
            callback(null, db)
        }

        function returnDb(err, success) {
            if (err) {
                return callback(err)
            }

            if (!success) {
                return callback(new Error("auth failed"))
            }

            callback(null, db)
        }
    }
}
309806
function() {

    this.childspawn = null;
    this.connected = false;
    this.uncertain = false;
    this.config = null;
    this.debug = true;
}
328531
function storage( serviceDbName, viewsManager ){
	//Call constructor from super class
	events.EventEmitter.call(this);	
	
	//this db name and handle
	this.serviceDbName = serviceDbName;	
	this.storageDb = null;
	
	this.getDbName = function(){
		return serviceDbName;
	};
	
	//Indicate whether the db didn't exist and was created 
	this.dbCreated = false;
	
	var self = this;	
	this.initCloudant = function( resolve, reject ){
		cloudant.db.get(self.serviceDbName, function(err, body) {
			if ( viewsManager && !_.isArray( viewsManager )){
				viewsManager = [viewsManager];
			}
			if (err ) {
				//Create it
				cloudant.db.create(self.serviceDbName,function(err,body){
					if ( err ){
						reject( "Unable to create db " + self.serviceDbName + ". Error is " + err );
					}else{
						self.dbCreated = true;
						self.storageDb = cloudant.use( serviceDbName );
						if ( viewsManager ){
							var bFound = false;
							_.forEach( viewsManager, function( manager ){
								//Create the design doc
								bFound = true;
								console.log("inserting design doc " + manager.designName );
								self.storageDb.insert( {'views' : manager.getViewsJson() }, manager.designName, function(err,b) {
									if (err) {
										reject( "Failed to create view: "+err);
									}else{
										resolve();
									}
								});
							});
							if ( !bFound ){
								//Nothing to do
								resolve();
							}
						}
					}
				});
			}else{
				self.storageDb = cloudant.use( self.serviceDbName );
				
				//Make sure that the design docs exists, if not create them now
				if ( viewsManager ){
					async.each( viewsManager, function( manager, callback ){
						self.storageDb.get( manager.designName, function( err, body){
							var rev = null;
							var recreateDesignDoc = false;
							if ( err ){
								recreateDesignDoc = true;
							}else{
								//Grab the design doc and check version
								var views = body.views;
								rev = body._rev;
								_.forEach( manager.viewDefs, function( viewDef ){
									if ( views.hasOwnProperty( viewDef.viewName) ){
										var version = views[viewDef.viewName ].version || 0;
										if ( version < viewDef.version ){
											recreateDesignDoc = true;
										}
									}else{
										recreateDesignDoc = true;
									}
								});
							}						
							if ( recreateDesignDoc ){
								var designDoc = {'views' : manager.getViewsJson() };
								if ( rev ){
									designDoc._rev = rev;
								}

								self.storageDb.insert( designDoc , manager.designName, function(err,b) {
									if (err) {
										callback( err );
									}else{
										callback();
									}
								});
							}else{
								callback();
							}
						});
					}, function(err){
						if ( err ){
							reject( "Failed to create view: "+err);
						}else{
							resolve();
						}
					});
				}else{
					resolve();
				}
			}
		});
	};
		
	when.promise( this.initCloudant )
		.then( function() {
			console.log("Cloudant database %s successfully initialized", self.serviceDbName);
			self.emit("cloudant_ready");
		})
		.otherwise( function(err) {
			console.log("Error initializing cloudant database " + err);
			self.emit("cloudant_error");
		});
	
	/**
	 * Return true if db is correctly initialized
	 */
	this.isDbInitialized = function(){
		return !!this.storageDb;
	};
	
	/**
	 * Destroy the current db
	 */
	this.destroy = function( callback ){
		this.run( function( err, db ){
			if ( err ){
				return callback(err);
			}
			cloudant.db.destroy( serviceDbName, function(err){
				if ( err ){
					return callback(err);
				}
				//Set as not initialized
				delete this.storageDb;
				return callback();
			}.bind(this));
		}.bind(this));
	}
	
	/**
	 * Destroy and recreate the database
	 * @param callback(err)
	 */
	this.destroyAndRecreate = function(callback){
		this.run( function( err, db ){
			if ( err ){
				return callback( err );
			}
			cloudant.db.destroy( serviceDbName, function( err ){
				if ( err ){
					return callback(err);
				}
				
				//Reinit
				when.promise( this.initCloudant )
				.then( function() {
					return callback( null );
				})
				.otherwise( function(err) {
					return callback( err );			
				})
			}.bind(this));
		}.bind(this));
	}
	
	this.run = function( callback ){
		if ( !self.storageDb ){
			var err = "Storage has not been correctly initialized";
			console.log( err );
			return callback( err );
		}
		
		return callback( null, self.storageDb );
	};
	
	this.savesInProgress = {};
	
	/**
	 * getDoc: helper function that fetch a document from the database
	 * @param docId: documentId
	 * @param callback(err, doc)
	 */
	this.getDoc = function( docId, callback ){
		this.run( function( err, db ){
			if ( err ){
				return callback(err);
			}
			db.get( docId, { include_docs: true }, callback );
		})
	};
	
	/**
	 * Update doc if exists, insert a new one if not
	 * @param: docId
	 * @param: callback(doc), return updated document
	 * @param: done( err, doc ) status callback
	 */
	this.upsert = function( docId, callback, done ){
		this.run( function( err, db ){
			if ( err ){
				return callback(err);
			}
			
			var insert = function( body ){
				//Let caller modify doc if already exists, caller can replace with entirely new doc, however, doc id will be reestablished if doc already exists
				var id = body && (body._id || body.id);
				var rev = body && (body._rev || body.rev);
				body = callback( body );				
				if ( body ){
					body._id = id || body._id || undefined;
					body._rev = rev || body._rev || undefined;
					
					db.insert( body, body._id, function( err, data ){
						if ( id && this.savesInProgress.hasOwnProperty( id )){
							delete this.savesInProgress[id];
						}
						if ( err ){
							console.log( "Error while saving doc: " + err + ".Doc id: " + body._id + " Doc rev: " + body._rev);
							return done(err);
						}
						//always set the id and rev if available
						body._id = (data && (data.id || data._id)) || body._id;
						body._rev = (data && (data.rev || data._rev)) || body._rev;
						return done( null, body );
					}.bind( this ));
				}else{
					//Caller didn't give us the data, return error
					return done("Error during upsert: Caller didn't return a valid document");
				}
			}.bind( this );
			
			if ( !docId ){
				return insert( null );
			}
			
			if ( this.savesInProgress.hasOwnProperty( docId ) ){
				this.savesInProgress[docId]++;
				//console.log("Deferring save of document: " + docId + " :::: " + this.savesInProgress[docId]);
				//Wait for the other save to finish
				return setTimeout( function(){
					return this.upsert( docId, callback, done );
				}.bind(this), this.savesInProgress[docId] * 500 );
			}

			//Mark this document as being saved
			this.savesInProgress[docId] = 1;
			
			//We have a docId, load it
			db.get( docId, { include_docs: true }, function( err, body ){				
				return insert( body );
			});
		}.bind(this));
	};
	
	/**
	 * Delete all docs in a view
	 */
	this.deleteDocsFromView = function( designName, viewName, callback ){
		//console.log("Deleting all docs in view: " + designName + " / " + viewName );
		this.run( function( err, db ){
			if ( err ){
				return callback( err );
			}
			async.waterfall([
                function( callback ){
                	db.view(designName, viewName, function(err, data) {
						if ( err ){
							return callback( err );
						}
						var docs = _.map( data.rows, function( row ){
							return {id: row.id || row.value._id, rev: row.value.rev||row.value._rev};
						});					
						return callback( null, docs );
                	});
                },
                function( docs, callback ){
                	if ( docs.length == 0 || docs[0].rev ){
                		//We either have no docs to delete, or rev is already retrieved
                		return callback( null, docs );
                	}
                	
                	//Call bulk api to fetch revs
                	db.fetchRevs( { keys: _.map( docs, function(doc){
                			return doc.id;
                		})}, function( err, body ){
                			if ( err ){
                				return callback( err );
                			}
                			return callback( null, _.map(body.rows, function( row ){
                					return {id:row.id, rev: row.value.rev};
                				}) 
                			);
                		}
                	);
                },
                function( docs, callback ){
                	//Delete all docs one by one
                	async.each( docs, function( doc, callback ){
                		db.destroy( doc.id, doc.rev, callback );
                	}, function( err ){
                		return callback( err );
                	});
                }],
                function( err, results ){
					return callback( err, results );
				}
			);
		});
	};
}
841068
function MongoAdapter(mongooseConnection) {
  if (!(this instanceof MongoAdapter)) {
    return new MongoAdapter(mongooseConnection);
  }

  storj.StorageAdapter.call(this);

  if (mongooseConnection instanceof Storage) {
    this._model = mongooseConnection.models.Shard;
  } else {
    this._model = Shard(mongooseConnection);
  }
}