js.syncbase: mojo.syncbase: syncbase+mojo: implement batches

Also updates JavaScript impl so that Mojo and JS impls:
- mirror one another, which will make them easier to maintain
- use subclassing for Database/BatchDatabase, which will result
in better dartdoc/jsdoc

MultiPart: 2/3

Change-Id: I32ee60fe585ac25341ba89f50356f99d3c328cc6
diff --git a/Makefile b/Makefile
index 738f54f..6ad52bc 100644
--- a/Makefile
+++ b/Makefile
@@ -128,18 +128,16 @@
 DOCSTRAP_LOC:= node_modules/ink-docstrap
 JS_SRC_FILES = $(shell find src -name "*.js" | sed 's/ /\\ /')
 docs: $(JS_SRC_FILES) ../core/jsdocs/docstrap-template/compiled/site.vanadium.css | node_modules
-	# Copy our compiled style template
+	# Copy our compiled style template.
 	cp -f ../core/jsdocs/docstrap-template/compiled/site.vanadium.css ${DOCSTRAP_LOC}/template/static/styles
 
-	# Build the docs
+	# Build the docs.
 	jsdoc $^ --readme ./jsdocs/index.md --configure ./jsdocs/conf.json --template ${DOCSTRAP_LOC}/template --destination $@
 
-	# Copy favicon
+	# Copy favicon.
 	cp -f ../core/jsdocs/favicon.ico $@
 
-# serve-docs
-#
-# Serve the docs at http://localhost:8020.
+# Serves the docs at http://localhost:8020.
 serve-docs: docs
 	static docs -p 8020
 
diff --git a/src/app.js b/src/app.js
index 3fdc0f2..6c80e1a 100644
--- a/src/app.js
+++ b/src/app.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+var inherits = require('inherits');
 var vanadium = require('vanadium');
 
 var Database = require('./nosql/database');
@@ -10,10 +11,10 @@
 
 var wireSignature = vdl.App.prototype._serviceDescription;
 
+inherits(App, util.NamedResource);
 module.exports = App;
 
 /**
- * @summary
  * App represents a collection of Databases.
  * Private constructor. Use service.app() to get an instance.
  * @param {string} parentFullName Full name of parent Service.
@@ -29,7 +30,7 @@
 
   var fullName = vanadium.naming.join(
     parentFullName, util.escape(relativeName));
-  util.addNameProperties(this, parentFullName, relativeName, fullName);
+  util.NamedResource.call(this, parentFullName, relativeName, fullName);
 
   // TODO(nlacasse): Use the prr module to simplify all the
   // 'Object.defineProperty' calls scattered throughout the project.
@@ -50,7 +51,7 @@
 // must not contain slashes. schema can be null or undefined only if a schema
 // was never set for the database in the first place.
 App.prototype.noSqlDatabase = function(relativeName, schema) {
-  return new Database(this.fullName, relativeName, '', schema);
+  return new Database(this.fullName, relativeName, schema);
 };
 
 // listDatabases returns of all database names.
diff --git a/src/nosql/abstract-database.js b/src/nosql/abstract-database.js
new file mode 100644
index 0000000..5a15028
--- /dev/null
+++ b/src/nosql/abstract-database.js
@@ -0,0 +1,166 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var inherits = require('inherits');
+var through2 = require('through2');
+var vanadium = require('vanadium');
+
+// TODO(nlacasse): We should expose unwrap and other type-util methods on the
+// vanadium.vdl object.
+var unwrap = require('vanadium/src/vdl/type-util').unwrap;
+
+var nosqlVdl = require('../gen-vdl/v.io/v23/services/syncbase/nosql');
+
+var Table = require('./table');
+var util = require('../util');
+
+inherits(AbstractDatabase, util.NamedResource);
+module.exports = AbstractDatabase;
+
+/**
+ * AbstractDatabase is a base class for Database and BatchDatabase. A database
+ * is a collection of Tables. Batches, queries, sync, watch, etc. all operate at
+ * the database level.
+ * Private constructor. Use app.noSqlDatabase() to get a Database, and
+ * database.beginBatch() to get a BatchDatabase.
+ * @param {string} parentFullName Full name of parent App.
+ * @param {string} relativeName Relative name for this Database.
+ * @param {string} batchSuffix Suffix for BatchDatabase, empty for non-batch
+ * Database.
+ * @param {number} schema Database schema expected by client.
+ * @constructor
+ * @inner
+ * @memberof {module:syncbase.nosql}
+ */
+function AbstractDatabase(parentFullName, relativeName, batchSuffix, schema) {
+  if (!(this instanceof AbstractDatabase)) {
+    return new AbstractDatabase(parentFullName, relativeName, batchSuffix,
+                                schema);
+  }
+
+  // Escape relativeName so that any forward slashes get dropped, thus ensuring
+  // that the server will interpret fullName as referring to a database object.
+  // Note that the server will still reject this name if util.ValidDatabaseName
+  // returns false.
+  var fullName = vanadium.naming.join(
+    parentFullName, util.escape(relativeName) + batchSuffix);
+  util.NamedResource.call(this, parentFullName, relativeName, fullName);
+
+  // TODO(sadovsky): The schema and schemaVersion fields should be private.
+  // Better yet, we shouldn't include any schema-related things in the JS client
+  // library until the design is more fully baked.
+  Object.defineProperty(this, 'schema', {
+    enumerable: false,
+    value: schema,
+    writable: false
+  });
+
+  Object.defineProperty(this, 'schemaVersion', {
+    enumerable: false,
+    value: schema ? schema.metadata.version : -1,
+    writable: false
+  });
+
+  /**
+   * Caches the database wire object.
+   * @private
+   */
+  Object.defineProperty(this, '_wireObj', {
+    enumerable: false,
+    value: null,
+    writable: true
+  });
+}
+
+/**
+ * @private
+ */
+AbstractDatabase.prototype._wire = function(ctx) {
+  if (this._wireObj) {
+    return this._wireObj;
+  }
+  var client = vanadium.runtimeForContext(ctx).getClient();
+  var signature = [nosqlVdl.Database.prototype._serviceDescription];
+
+  this._wireObj = client.bindWithSignature(this.fullName, signature);
+  return this._wireObj;
+};
+
+
+/**
+ * Returns the Table with the given relative name.
+ * @param {string} relativeName Table name.  Must not contain slashes.
+ * @return {module:syncbase.table.Table} Table object.
+ */
+AbstractDatabase.prototype.table = function(relativeName) {
+  return new Table(this.fullName, relativeName, this.schemaVersion);
+};
+
+/**
+ * Returns a list of all Table names.
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {function} cb Callback.
+ */
+AbstractDatabase.prototype.listTables = function(ctx, cb) {
+  // See comment in v.io/v23/services/syncbase/nosql/service.vdl for why we
+  // can't implement listTables using Glob (via util.listChildren).
+  this._wire(ctx).listTables(ctx, cb);
+};
+
+/**
+ * Executes a syncQL query.
+ *
+ * Returns a stream of rows.  The first row contains an array of headers (i.e.
+ * column names).  Subsequent rows contain an array of values for each row that
+ * matches the query.  The number of values returned in each row will match the
+ * size of the headers array.
+ * Concurrency semantics: It is legal to perform writes concurrently with
+ * Exec. The returned stream reads from a consistent snapshot taken at the
+ * time of the RPC, and will not reflect subsequent writes to keys not yet
+ * reached by the stream.
+ *
+ * NOTE(nlacasse): The Go client library returns the headers seperately from
+ * the stream.  We could potentially do something similar in JavaScript, by
+ * pulling the headers off the stream and passing them to the callback.
+ * However, by Vanadium JS convention the callback gets called at the *end* of
+ * the RPC, so a developer would have to wait for the stream to finish before
+ * seeing what the headers are, which is not ideal.  We also cannot return the
+ * headers directly because reading from the stream is async.
+ *
+ * TODO(nlacasse): Syncbase queries don't work on values that were put without
+ * type information.  When JavaScript encodes values with no type infomation,
+ * it uses "vdl.Value" for the type.  Presumably, syncbase does not know how to
+ * decode such objects, so queries that involve inspecting the object or its
+ * type don't work.
+ *
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {string} query Query string.
+ * @param {function} cb Callback.
+ * @returns {stream} Stream of rows.
+ */
+AbstractDatabase.prototype.exec = function(ctx, query, cb) {
+  var streamUnwrapper = through2({
+    objectMode: true
+  }, function(res, enc, cb) {
+    return cb(null, res.map(unwrap));
+  });
+
+  var stream = this._wire(ctx).exec(ctx, this.schemaVersion, query, cb).stream;
+
+  var decodedStream = stream.pipe(streamUnwrapper);
+  stream.on('error', function(err) {
+    decodedStream.emit('error', err);
+  });
+
+  return decodedStream;
+};
+
+/**
+ * Gets the ResumeMarker that points to the current end of the event log.
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {function} cb Callback.
+ */
+AbstractDatabase.prototype.getResumeMarker = function(ctx, cb) {
+  this._wire(ctx).getResumeMarker(ctx, cb);
+};
diff --git a/src/nosql/batch-database.js b/src/nosql/batch-database.js
deleted file mode 100644
index ad017a1..0000000
--- a/src/nosql/batch-database.js
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-module.exports = BatchDatabase;
-
-/*
- * A handle to a set of reads and writes to the database that should be
- * considered an atomic unit. See beginBatch() for concurrency semantics.
- *
- * This constructor is private.  Use [database.beginBatch]{@link
- * module:syncbase.nosql.Database.beginBatch} or [nosql.runInBatch]{@link
- * module:syncbase.nosql~runInBatch} instead.
- * @constructor
- * @inner
- * @param {module:syncbase.database.Database} db Database.
- * @param {number} schemaVersion Database schema version expected by client.
- */
-function BatchDatabase(db, schemaVersion) {
-  if (!(this instanceof BatchDatabase)) {
-    return new BatchDatabase(db, schemaVersion);
-  }
-
-  this.schemaVersion = schemaVersion;
-  Object.defineProperty(this, '_db', {
-    enumerable: false,
-    value: db,
-    writeable: false
-  });
-}
-
-/**
- * Returns the Table with the given name.
- * @param {string} relativeName Table name.  Must not contain slashes.
- * @return {module:syncbase.table.Table} Table object.
- */
-BatchDatabase.prototype.table = function(relativeName) {
-  return this._db.table(relativeName);
-};
-
-/**
- * Returns a list of all Table names.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-BatchDatabase.prototype.listTables = function(ctx, cb) {
-  this._db.listTables(ctx, cb);
-};
-
-/**
- * Persists the pending changes to the database.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-BatchDatabase.prototype.commit = function(ctx, cb) {
-  this._db._wire(ctx).commit(ctx, this.schemaVersion, cb);
-};
-
-/**
- * Notifies the server that any pending changes can be discarded.  It is not
- * strictly required, but it may allow the server to release locks or other
- * resources sooner than if it was not called.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-BatchDatabase.prototype.abort = function(ctx, cb) {
-  this._db._wire(ctx).abort(ctx, this.schemaVersion, cb);
-};
-
-/**
- * Executes a syncQL query.
- *
- * Returns a stream of rows.  The first row contains an array of headers (i.e.
- * column names).  Subsequent rows contain an array of values for each row that
- * matches the query.  The number of values returned in each row will match the
- * size of the headers array.
- *
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {string} query Query string.
- * @param {function} cb Callback.
- * @returns {stream} Stream of rows.
- */
-BatchDatabase.prototype.exec = function(ctx, query, cb) {
-  return this._db.exec(ctx, query, cb);
-};
-
-/**
- * Gets the ResumeMarker that points to the current end of the event log.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-BatchDatabase.prototype.getResumeMarker = function(ctx, cb) {
-  this._db.getResumeMarker(ctx, cb);
-};
diff --git a/src/nosql/batch.js b/src/nosql/batch.js
index 157a21d..15e9f3f 100644
--- a/src/nosql/batch.js
+++ b/src/nosql/batch.js
@@ -2,10 +2,58 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-module.exports = runInBatch;
+var inherits = require('inherits');
+
+var AbstractDatabase = require('./abstract-database');
+
+inherits(BatchDatabase, AbstractDatabase);
+module.exports = {
+  BatchDatabase: BatchDatabase,
+  runInBatch: runInBatch
+};
 
 /**
- * @summary
+ * BatchDatabase is a handle to a set of reads and writes to the database that
+ * should be considered an atomic unit. See database.beginBatch() for
+ * concurrency semantics.
+ * Private constructor. Use database.beginBatch() to get a BatchDatabase.
+ * @param {string} parentFullName Full name of parent App.
+ * @param {string} relativeName Relative name for this Database.
+ * @param {string} batchSuffix Suffix for this BatchDatabase.
+ * @param {number} schema Database schema expected by client.
+ * @constructor
+ * @inner
+ * @memberof {module:syncbase.nosql}
+ */
+function BatchDatabase(parentFullName, relativeName, batchSuffix, schema) {
+  if (!(this instanceof BatchDatabase)) {
+    return new BatchDatabase(parentFullName, relativeName, batchSuffix, schema);
+  }
+  AbstractDatabase.call(this, parentFullName, relativeName, batchSuffix,
+                        schema);
+}
+
+/**
+ * Persists the pending changes to the database.
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {function} cb Callback.
+ */
+BatchDatabase.prototype.commit = function(ctx, cb) {
+  this._wire(ctx).commit(ctx, this.schemaVersion, cb);
+};
+
+/**
+ * Notifies the server that any pending changes can be discarded.  It is not
+ * strictly required, but it may allow the server to release locks or other
+ * resources sooner than if it was not called.
+ * @param {module:vanadium.context.Context} ctx Vanadium context.
+ * @param {function} cb Callback.
+ */
+BatchDatabase.prototype.abort = function(ctx, cb) {
+  this._wire(ctx).abort(ctx, this.schemaVersion, cb);
+};
+
+/**
  * runInBatch runs a function with a newly created batch. If the function
  * errors, the batch is aborted. If the function succeeds, the batch is
  * committed.
@@ -41,6 +89,7 @@
 
   function retryLoop(i) {
     attempt(function(err) {
+      // TODO(sadovsky): Only retry if err is ErrConcurrentTransaction.
       if (err && i < 2) {
         retryLoop(i + 1);
       } else {
diff --git a/src/nosql/database.js b/src/nosql/database.js
index 07c2313..0a8cd7b 100644
--- a/src/nosql/database.js
+++ b/src/nosql/database.js
@@ -2,91 +2,45 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+var inherits = require('inherits');
 var through2 = require('through2');
 var vanadium = require('vanadium');
-// TODO(nlacasse): We should expose unwrap and other type-util methods on the
-// vanadium.vdl object.
-var unwrap = require('vanadium/src/vdl/type-util').unwrap;
+
 var verror = vanadium.verror;
 
-var nosqlVdl = require('../gen-vdl/v.io/v23/services/syncbase/nosql');
 var watchVdl = require('../gen-vdl/v.io/v23/services/watch');
 
-var BatchDatabase = require('./batch-database');
+var AbstractDatabase = require('./abstract-database');
+var BatchDatabase = require('./batch').BatchDatabase;
 /* jshint -W079 */
 // Silence jshint's error about redefining 'Blob'.
 var Blob = require('./blob');
 /* jshint +W079 */
 var Syncgroup = require('./syncgroup');
-var Table = require('./table');
-var util = require('../util');
 var watch = require('./watch');
 
+inherits(Database, AbstractDatabase);
 module.exports = Database;
 
 /**
- * @summary
- * Database represents a collection of Tables. Batches, queries, sync, watch,
- * etc. all operate at the Database level.
+ * Database is a collection of Tables. Batches, queries, sync, watch, etc. all
+ * operate at the Database level.
  * Private constructor. Use app.noSqlDatabase() to get an instance.
  * @param {string} parentFullName Full name of parent App.
  * @param {string} relativeName Relative name for this Database.
- * @param {number} schemaVersion Database schema version expected by client.
+ * @param {number} schema Database schema expected by client.
  * @constructor
  * @inner
  * @memberof {module:syncbase.nosql}
  */
-function Database(parentFullName, relativeName, batchSuffix, schema) {
+function Database(parentFullName, relativeName, schema) {
   if (!(this instanceof Database)) {
-    return new Database(parentFullName, relativeName);
+    return new Database(parentFullName, relativeName, schema);
   }
-
-  // Escape relativeName so that any forward slashes get dropped, thus ensuring
-  // that the server will interpret fullName as referring to a database object.
-  // Note that the server will still reject this name if util.ValidDatabaseName
-  // returns false.
-  var fullName = vanadium.naming.join(
-    parentFullName, util.escape(relativeName) + batchSuffix);
-  util.addNameProperties(this, parentFullName, relativeName, fullName);
-
-  Object.defineProperty(this, 'schema', {
-    enumerable: false,
-    value: schema,
-    writable: false
-  });
-
-  Object.defineProperty(this, 'schemaVersion', {
-    enumerable: false,
-    value: schema ? schema.metadata.version : -1,
-    writable: false
-  });
-
-  /**
-   * Caches the database wire object.
-   * @private
-   */
-  Object.defineProperty(this, '_wireObj', {
-    enumerable: false,
-    value: null,
-    writable: true
-  });
+  AbstractDatabase.call(this, parentFullName, relativeName, '', schema);
 }
 
 /**
- * @private
- */
-Database.prototype._wire = function(ctx) {
-  if (this._wireObj) {
-    return this._wireObj;
-  }
-  var client = vanadium.runtimeForContext(ctx).getClient();
-  var signature = [nosqlVdl.Database.prototype._serviceDescription];
-
-  this._wireObj = client.bindWithSignature(this.fullName, signature);
-  return this._wireObj;
-};
-
-/**
  * Creates this Database.
  * @param {module:vanadium.context.Context} ctx Vanadium context.
  * @param {module:vanadium.security.access.Permissions} perms Permissions for
@@ -123,82 +77,26 @@
 };
 
 /**
- * Executes a syncQL query.
- *
- * Returns a stream of rows.  The first row contains an array of headers (i.e.
- * column names).  Subsequent rows contain an array of values for each row that
- * matches the query.  The number of values returned in each row will match the
- * size of the headers array.
- * Concurrency semantics: It is legal to perform writes concurrently with
- * Exec. The returned stream reads from a consistent snapshot taken at the
- * time of the RPC, and will not reflect subsequent writes to keys not yet
- * reached by the stream.
- *
- * NOTE(nlacasse): The Go client library returns the headers seperately from
- * the stream.  We could potentially do something similar in JavaScript, by
- * pulling the headers off the stream and passing them to the callback.
- * However, by Vanadium JS convention the callback gets called at the *end* of
- * the RPC, so a developer would have to wait for the stream to finish before
- * seeing what the headers are, which is not ideal.  We also cannot return the
- * headers directly because reading from the stream is async.
- *
- * TODO(nlacasse): Syncbase queries don't work on values that were put without
- * type information.  When JavaScript encodes values with no type infomation,
- * it uses "vdl.Value" for the type.  Presumably, syncbase does not know how to
- * decode such objects, so queries that involve inspecting the object or its
- * type don't work.
- *
+ * Replaces the current Permissions for the Database.
  * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {string} query Query string.
+ * @param {module:vanadium.security.access.Permissions} perms Permissions for
+ * the database.
+ * @param {string} version Version of the current Permissions object which will
+ * be overwritten. If empty, SetPermissions will perform an unconditional
+ * update.
  * @param {function} cb Callback.
- * @returns {stream} Stream of rows.
  */
-Database.prototype.exec = function(ctx, query, cb) {
-  var streamUnwrapper = through2({
-    objectMode: true
-  }, function(res, enc, cb) {
-    return cb(null, res.map(unwrap));
-  });
-
-  var stream = this._wire(ctx).exec(ctx, this.schemaVersion, query, cb).stream;
-
-  var decodedStream = stream.pipe(streamUnwrapper);
-  stream.on('error', function(err) {
-    decodedStream.emit('error', err);
-  });
-
-  return decodedStream;
+Database.prototype.setPermissions = function(ctx, perms, version, cb) {
+  this._wire(ctx).setPermissions(ctx, perms, version, cb);
 };
 
 /**
- * Returns the Table with the given name.
- * @param {string} relativeName Table name.  Must not contain slashes.
- * @return {module:syncbase.table.Table} Table object.
- */
-Database.prototype.table = function(relativeName) {
-  return new Table(this.fullName, relativeName, this.schemaVersion);
-};
-
-/**
- * Returns a list of all Table names.
+ * Returns the current Permissions for the Database.
  * @param {module:vanadium.context.Context} ctx Vanadium context.
  * @param {function} cb Callback.
  */
-Database.prototype.listTables = function(ctx, cb) {
-  // See comment in v.io/v23/services/syncbase/nosql/service.vdl for why we
-  // can't implement listTables using Glob (via util.listChildren).
-  this._wire(ctx).listTables(ctx, cb);
-};
-
-/**
- * @private
- */
-Database.prototype._tableWire = function(ctx, relativeName) {
-  var client = vanadium.runtimeForContext(ctx).newClient();
-  var signature = [nosqlVdl.Table.prototype._serviceDescription];
-
-  var fullTableName = vanadium.naming.join(this.fullName, relativeName);
-  return client.bindWithSignature(fullTableName, signature);
+Database.prototype.getPermissions = function(ctx, cb) {
+  this._wire(ctx).getPermissions(ctx, cb);
 };
 
 /**
@@ -271,38 +169,6 @@
 };
 
 /**
- * Gets the ResumeMarker that points to the current end of the event log.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-Database.prototype.getResumeMarker = function(ctx, cb) {
-  this._wire(ctx).getResumeMarker(ctx, cb);
-};
-
-/**
- * Replaces the current Permissions for the Database.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {module:vanadium.security.access.Permissions} perms Permissions for
- * the database.
- * @param {string} version Version of the current Permissions object which will
- * be overwritten. If empty, SetPermissions will perform an unconditional
- * update.
- * @param {function} cb Callback.
- */
-Database.prototype.setPermissions = function(ctx, perms, version, cb) {
-  this._wire(ctx).setPermissions(ctx, perms, version, cb);
-};
-
-/**
- * Returns the current Permissions for the Database.
- * @param {module:vanadium.context.Context} ctx Vanadium context.
- * @param {function} cb Callback.
- */
-Database.prototype.getPermissions = function(ctx, cb) {
-  this._wire(ctx).getPermissions(ctx, cb);
-};
-
-/**
  * Creates a new batch. Instead of calling this function directly, clients are
  * encouraged to use the RunInBatch() helper function, which detects "concurrent
  * batch" errors and handles retries internally.
@@ -332,9 +198,8 @@
       if (err) {
         return cb(err);
       }
-      var db = new Database(self._parentFullName, self.name, batchSuffix,
-                            self.schema);
-      return cb(null, new BatchDatabase(db));
+      return cb(null, new BatchDatabase(
+        self._parentFullName, self.name, batchSuffix, self.schema));
     });
 };
 
@@ -466,7 +331,6 @@
 /**
  * Returns a handle to the blob with the given blobRef.
  * @param {module:syncbase.nosql.BlobRef} blobRef BlobRef of blob to get.
- *
  */
 Database.prototype.blob = function(blobRef) {
   return new Blob(this, blobRef);
@@ -476,7 +340,6 @@
  * Creates a new blob.
  * @param {module:vanadium.context.Context} ctx Vanadium context.
  * @param {function} cb Callback.
- *
  */
 Database.prototype.createBlob = function(ctx, cb) {
   var self = this;
diff --git a/src/nosql/index.js b/src/nosql/index.js
index e532201..3ba0af2 100644
--- a/src/nosql/index.js
+++ b/src/nosql/index.js
@@ -3,13 +3,12 @@
 // license that can be found in the LICENSE file.
 
 var rowrange = require('./rowrange');
-var runInBatch = require('./batch');
+var runInBatch = require('./batch').runInBatch;
 var Schema = require('./schema');
 var vdl = require('../gen-vdl/v.io/v23/services/syncbase/nosql');
 var watch = require('./watch');
 
 /**
- * @summary
  * Defines the client API for the NoSQL part of Syncbase.
  * @namespace
  * @name nosql
diff --git a/src/nosql/row.js b/src/nosql/row.js
index c2702ec..33cc127 100644
--- a/src/nosql/row.js
+++ b/src/nosql/row.js
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+var inherits = require('inherits');
 var vanadium = require('vanadium');
 
 var nosqlVdl = require('../gen-vdl/v.io/v23/services/syncbase/nosql');
 var util = require('../util');
 
+inherits(Row, util.NamedResource);
 module.exports = Row;
 
 /**
- * @summary
  * Row represents a single row in a Table.
  * Private constructor. Use table.row() to get an instance.
  * @param {string} parentFullName Full name of parent Table.
@@ -28,7 +29,7 @@
   // Note, we immediately unescape row keys on the server side. See comment in
   // server/nosql/dispatcher.go for explanation.
   var fullName = vanadium.naming.join(parentFullName, util.escape(key));
-  util.addNameProperties(this, parentFullName, key, fullName);
+  util.NamedResource.call(this, parentFullName, key, fullName);
 
   this.schemaVersion = schemaVersion;
 
diff --git a/src/nosql/rowrange.js b/src/nosql/rowrange.js
index d859cc9..60ca9ea 100644
--- a/src/nosql/rowrange.js
+++ b/src/nosql/rowrange.js
@@ -5,7 +5,6 @@
 var util = require('../util');
 
 /**
- * @summary
  * Provides utility methods to create different rowranges.
  * @namespace
  * @name rowrange
@@ -33,7 +32,7 @@
 }
 
 /**
- * Creates a range that only matches items of the given prefix.
+ * Creates a range that only matches rows with the given prefix.
  * @param {string} prefix Prefix.
  * @return {module:syncbase.nosql~Range} A Range object covering the prefix.
  * inherits from {@link module:syncbase.nosql~RowRange}
@@ -58,7 +57,6 @@
 }
 
 /*
- * @summary
  * Represents a range of row values.
  * Private constructor. Use one of the utility methods such as
  * {@link module:syncbase.nosql.rowrange#rowrange},
diff --git a/src/nosql/table.js b/src/nosql/table.js
index ea6190c..bfd599a 100644
--- a/src/nosql/table.js
+++ b/src/nosql/table.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+var inherits = require('inherits');
 var through2 = require('through2');
 var vanadium = require('vanadium');
 
@@ -12,10 +13,10 @@
 
 var prefix = RowRange.prefix;
 
+inherits(Table, util.NamedResource);
 module.exports = Table;
 
 /**
- * @summary
  * Table represents a collection of Rows.
  * Private constructor. Use database.table() to get an instance.
  * @param {string} parentFullName Full name of parent Database.
@@ -36,7 +37,7 @@
   // returns false.
   var fullName = vanadium.naming.join(
     parentFullName, util.escape(relativeName));
-  util.addNameProperties(this, parentFullName, relativeName, fullName);
+  util.NamedResource.call(this, parentFullName, relativeName, fullName);
 
   this.schemaVersion = schemaVersion;
 
diff --git a/src/service.js b/src/service.js
index 48c9469..29a474d 100644
--- a/src/service.js
+++ b/src/service.js
@@ -9,14 +9,13 @@
 var vdl = require('./gen-vdl/v.io/v23/services/syncbase');
 
 // TODO(aghassemi): This looks clunky,
-// https://github.com/vanadium/issues/issues/499 to deal with it.
+// See https://github.com/vanadium/issues/issues/499.
 var wireSignature = vdl.Service.prototype._serviceDescription;
 
 module.exports = Service;
 
 /**
- * @summary
- * Service represents a collection of Apps.
+ * Service represents a collection of apps.
  * @param {string} fullName Full Vanadium object name of this Service.
  * @constructor
  * @inner
diff --git a/src/util.js b/src/util.js
index 56aed63..19e4928 100644
--- a/src/util.js
+++ b/src/util.js
@@ -5,7 +5,7 @@
 var vanadium = require('vanadium');
 
 module.exports = {
-  addNameProperties: addNameProperties,
+  NamedResource: NamedResource,
   listChildren: listChildren,
   prefixRangeLimit: prefixRangeLimit,
   stringToUTF8Bytes: stringToUTF8Bytes,
@@ -14,17 +14,22 @@
 };
 
 /**
- * Creates public 'name' and 'fullName' properties on an object, as well as a
- * private '_parentFullName' property.
- * @private
+ * NamedResource is a base class for Syncbase layers with names.
+ * @param {string} parentFullName Full name of parent layer.
+ * @param {string} name Relative name for this layer.
+ * @param {string} fullName Full name for this layer.
  */
-function addNameProperties(self, parentFullName, name, fullName) {
+function NamedResource(parentFullName, name, fullName) {
+  if (!(this instanceof NamedResource)) {
+    return new NamedResource(parentFullName, name, fullName);
+  }
+
   /**
    * @property _parentFullName
    * @private
    * @type {string}
    */
-  Object.defineProperty(self, '_parentFullName', {
+  Object.defineProperty(this, '_parentFullName', {
     value: parentFullName,
     writable: false,
     enumerable: false
@@ -34,7 +39,7 @@
    * @property name
    * @type {string}
    */
-  Object.defineProperty(self, 'name', {
+  Object.defineProperty(this, 'name', {
     value: name,
     writable: false,
     enumerable: true
@@ -44,7 +49,7 @@
    * @property fullName
    * @type {string}
    */
-  Object.defineProperty(self, 'fullName', {
+  Object.defineProperty(this, 'fullName', {
     value: fullName,
     writable: false,
     enumerable: true
diff --git a/test/integration/test-batch.js b/test/integration/test-batch.js
index 7093571..dd02e30 100644
--- a/test/integration/test-batch.js
+++ b/test/integration/test-batch.js
@@ -5,7 +5,7 @@
 var async = require('async');
 var test = require('prova');
 
-var BatchDatabase = require('../../src/nosql/batch-database');
+var BatchDatabase = require('../../src/nosql/batch').BatchDatabase;
 
 var nosql = require('../..').nosql;
 var BatchOptions = nosql.BatchOptions;
@@ -32,8 +32,8 @@
       }
 
       t.ok(batch instanceof BatchDatabase, 'batch is a BatchDatabase');
-      t.notEqual(batch.name, o.database.name,
-                 'batch has different name than database');
+      t.equal(batch.name, o.database.name,
+              'batch name should match database name');
       t.notEqual(batch.fullName, o.database.fullName,
                  'batch has different fullName than database');