Permalink
Browse files

abstracted db constructor

cleans up autocomplete too
  • Loading branch information...
aheckmann committed Jan 26, 2013
1 parent f98f3f9 commit b7fa322289195ff10005ea140a71f09f861401f8
Showing with 276 additions and 60 deletions.
  1. +12 −53 lib/createContext.js
  2. +235 −0 lib/db.js
  3. +3 −6 lib/index.js
  4. +24 −0 lib/p.js
  5. +2 −1 package.json
View
@@ -1,22 +1,14 @@
var debug = require('./debug');
var log = require('./log')
-var util = require('util')
+var p = require('./p')
module.exports = exports = function (db, term, cb) {
var context = term.context;
-
- // TODO move me
- db.constructor.prototype.inspect = function () {
- return this.databaseName;
- }
-
context.db = db;
context.use = function (name) {
debug('use db [' + name + ']');
-
- term.context.db = db = db.db(name);
- collections({ silent: true });
+ term.context.db = db = db.use(name);
term.displayPrompt();
return db;
}
@@ -31,39 +23,13 @@ module.exports = exports = function (db, term, cb) {
options = {};
}
- db.collectionNames({ namesOnly: true }, function (err, names) {
+ db.collections(function (err, names) {
if (err) {
console.error(err.stack);
return term.displayPrompt();
}
- if (!Array.isArray(names)) {
- names = [];
- }
-
- // remove cached collections
- if (Array.isArray(db.__collections__)) {
- db.__collections__.forEach(function (name) {
- delete db[name];
- });
- }
-
- // strip db from name
- var ns = db.databaseName;
- var len = ns.length + 1;
- names = names.map(function (name) {
- return name.substring(len);
- });
-
- db.__collections__ = names;
-
- // expose access from db
- names.forEach(function (name) {
- db[name] = db.collection(name);
- });
-
if (cb) return cb(err, names);
-
if (!names.length) return;
if (options.silent) return;
@@ -84,8 +50,9 @@ module.exports = exports = function (db, term, cb) {
cb = rich, rich = false;
}
- db.executeDbAdminCommand({ listDatabases: 1 }, {}, function (err, dbs) {
+ db.runCommand({ listDatabases: 1 }, { admin: true }, function (err, dbs) {
if (cb) return cb(err, dbs);
+
if (err) {
console.error(err.stack);
return term.displayPrompt();
@@ -120,19 +87,23 @@ module.exports = exports = function (db, term, cb) {
});
}
term.displayPrompt();
- });
+ })
}
var show = context.show = {};
+
Object.defineProperty(show, 'dbs', {
get: dbs
})
+
Object.defineProperty(show, 'collections', {
get: collections
})
+
Object.defineProperty(show, 'tables', {
get: collections
})
+
Object.defineProperty(context, 'exit', {
get: function () {
db.close(function () {
@@ -145,18 +116,7 @@ module.exports = exports = function (db, term, cb) {
* Query result print helper
*/
- context.p = function () {
- console.log();
- ;[].slice.call(arguments).forEach(function (arg, i) {
- var out = util.inspect(arg, false, 100, true);
- if (i === 0) {
- console.log('error: ', out);
- } else {
- console.log(out);
- }
- });
- term.displayPrompt();
- }
+ context.p = p;
// add dbs to the use function for autocomplete
dbs(function (err, res) {
@@ -174,8 +134,7 @@ module.exports = exports = function (db, term, cb) {
});
});
- // hook up default database collection getters on `db`
- collections({ silent: true });
+ // TODO refresh database list after dropping a db
cb();
});
View
235 lib/db.js
@@ -0,0 +1,235 @@
+
+/**
+ * Dependencies
+ */
+
+var mongodb = require('mongodb')
+var slice = require('sliced')
+var p = require('./p')
+
+/**
+ * Expose
+ */
+
+module.exports = exports = create;
+
+function create (db) {
+ var DB = createConstructor(db);
+ return new DB;
+}
+
+/**
+ * We create DB constructors dynamically to avoid
+ * assigning the db or collections directly to the
+ * database instance, thereby avoiding them displaying
+ * in autocomplete mixed together with the collection
+ * names.
+ *
+ * @param {Database} db
+ * @return {Function}
+ */
+
+function createConstructor (db) {
+ var collections = [];
+
+ function DB () {
+ this.collections();
+ }
+
+ /**
+ * Drop this database
+ */
+
+ DB.prototype.drop = function (cb) {
+ var name = db.databaseName;
+
+ db.dropDatabase(cb || function (err, worked) {
+ if (err) {
+ return console.error(err);
+ }
+ console.log('database %s was dropped', name);
+ });
+
+ return this;
+ }
+
+ /**
+ * Close this database connection
+ */
+
+ DB.prototype.close = function (force, cb) {
+ var args = slice(arguments);
+ var last = args[args.length];
+
+ if ('function' != typeof last) {
+ args.push(handleError);
+ }
+
+ db.close.apply(db, args);
+ return this;
+ }
+
+ /**
+ * Use a different database
+ */
+
+ DB.prototype.use = function (name) {
+ return create(db.db(name));
+ }
+
+ /**
+ * console.log helper
+ */
+
+ DB.prototype.inspect = function () {
+ return db.databaseName;
+ }
+
+ /**
+ * Refresh and return the list of collections on this database
+ */
+
+ DB.prototype.collections = function (cb) {
+ var self = this;
+
+ db.collectionNames({ namesOnly: true }, function (err, names) {
+ if (err) {
+ if (cb) return cb(err);
+ console.error(err.stack);
+ return;
+ }
+
+ if (!Array.isArray(names)) {
+ names = [];
+ }
+
+ // remove cached collections
+ collections.forEach(function (name) {
+ delete self[name];
+ });
+
+ // strip db from name
+ var ns = db.databaseName;
+ var len = ns.length + 1;
+ names = names.map(function (name) {
+ return name.substring(len);
+ });
+
+ collections = names;
+
+ // expose collection access from `db`
+ // TODO abstract collection
+ names.forEach(function (name) {
+ self[name] = db.collection(name);
+ });
+
+ if (cb) return cb(err, names);
+ });
+
+ return this;
+ }
+
+ /**
+ * Execute a command on the database
+ *
+ * @param {Object} cmd
+ * @param {Object} [opts]
+ * @param {Function} [cb]
+ */
+
+ DB.prototype.runCommand = function (cmd, opts, cb) {
+ if ('function' == typeof opts) {
+ cb = opts;
+ opts = {};
+ }
+
+ if (!cmd) {
+ var err = new Error('missing command');
+ if (cb) return cb(err);
+ console.error(err);
+ return;
+ }
+
+ if (!cb) cb = p;
+ if (!opts) opts = {};
+
+ var admin = !! opts.admin;
+ delete opts.admin;
+
+ var method = admin
+ ? 'executeDbAdminCommand'
+ : 'executeDbCommand'
+
+ db[method](cmd, opts, cb);
+ return this;
+ }
+
+ return DB;
+
+}
+
+/**
+ * Error reporting helper
+ */
+
+function handleError (err) {
+ if (err) {
+ return console.error(err);
+ }
+}
+
+/**
+ * use.database
+ *
+ * db.drop()
+ * db.close() // cloneDatabase()
+ * db.copy() // copyDatabase()
+ * db.help() // make combination of help() & db.listCommands()
+ * db.eval()
+ * db.createCollection()
+ * db.collection.find()
+ * db.collectionNames() // getCollectionNames
+ *
+ * db.addUser()
+ * db.removeUser()
+ * db.auth()
+ * db.logout()
+ * db.changeUserPassword()
+ *
+ * db.runCommand()
+ * db.adminCommand() ?
+ *
+ * db.repair() // db.repairDatabase()
+ * db.killOp()
+ * db.currentOp()
+ * db.fsyncLock()
+ * db.fsyncUnlock()
+ *
+ * db.stats()
+ * db.profilingLevel() // with args is a setter, else getter
+ * db.readPref()
+ *
+ * db.loadServerScripts() // from system.js collection into the shell
+ *
+ * // belongs on a server object
+ * .isMaster()
+ * .status() // .serverStatus()
+ * .shutdown() // .shutdownServer()
+ * .hostInfo()
+ * .version()
+ * .cmdLineOpts // .serverCmdLineOpts()
+ *
+ * // unclear
+ * db.getReplicationInfo()
+ * db.printReplicationInfo()
+ * db.printShardingStatus()
+ * db.printSlaveReplicationInfo()
+ * db.getLastErrorCmd()
+ * db.getLastErrorObj()
+ * db.getPrevError()
+ * db.getLastError()
+ *
+ * // belongs on collections
+ * .cloneCollection()
+ */
+
Oops, something went wrong.

0 comments on commit b7fa322

Please sign in to comment.