syncbase: naming change follow-ups
MultiPart: 4/7
Change-Id: I9d0f9e317aa7df18907a22befad8b924d5dc8751
diff --git a/src/gen-vdl/v.io/v23/services/syncbase/index.js b/src/gen-vdl/v.io/v23/services/syncbase/index.js
index 9102a01..580d040 100644
--- a/src/gen-vdl/v.io/v23/services/syncbase/index.js
+++ b/src/gen-vdl/v.io/v23/services/syncbase/index.js
@@ -20,11 +20,6 @@
// Types:
-var _type1 = new vdl.Type();
-_type1.kind = vdl.kind.LIST;
-_type1.name = "";
-_type1.elem = vdl.types.STRING;
-_type1.freeze();
@@ -53,11 +48,6 @@
-Service.prototype.listApps = function(ctx, serverCall) {
- throw new Error('Method ListApps not implemented');
-};
-
-
Service.prototype.setPermissions = function(ctx, serverCall, perms, version) {
throw new Error('Method SetPermissions not implemented');
};
@@ -83,22 +73,6 @@
{
- name: 'ListApps',
- doc: "// ListApps returns a list of all App names.\n// TODO(sadovsky): Maybe switch to streaming RPC.",
- inArgs: [],
- outArgs: [{
- name: '',
- doc: "",
- type: _type1
- },
- ],
- inStream: null,
- outStream: null,
- tags: [canonicalize.reduce(new access.Tag("Read", true), new access.Tag()._type), ]
- },
-
-
- {
name: 'SetPermissions',
doc: "// SetPermissions replaces the current Permissions for an object. version\n// allows for optional, optimistic concurrency control. If non-empty,\n// version's value must come from GetPermissions. If any client has\n// successfully called SetPermissions in the meantime, the version will be\n// stale and SetPermissions will fail. If empty, SetPermissions performs an\n// unconditional update.\n//\n// Permissions objects are expected to be small. It is up to the\n// implementation to define the exact limit, though it should probably be\n// around 100KB. Large lists of principals can be represented concisely using\n// blessings.\n//\n// There is some ambiguity when calling SetPermissions on a mount point.\n// Does it affect the mount itself or does it affect the service endpoint\n// that the mount points to? The chosen behavior is that it affects the\n// service endpoint. To modify the mount point's Permissions, use\n// ResolveToMountTable to get an endpoint and call SetPermissions on that.\n// This means that clients must know when a name refers to a mount point to\n// change its Permissions.",
inArgs: [{
@@ -164,11 +138,6 @@
};
-App.prototype.listDatabases = function(ctx, serverCall) {
- throw new Error('Method ListDatabases not implemented');
-};
-
-
App.prototype.setPermissions = function(ctx, serverCall, perms, version) {
throw new Error('Method SetPermissions not implemented');
};
@@ -232,23 +201,7 @@
],
inStream: null,
outStream: null,
- tags: [canonicalize.reduce(new access.Tag("Read", true), new access.Tag()._type), ]
- },
-
-
- {
- name: 'ListDatabases',
- doc: "// ListDatabases returns a list of all Database names.\n// TODO(kash): Include the database type (NoSQL vs. SQL).\n// TODO(sadovsky): Maybe switch to streaming RPC.",
- inArgs: [],
- outArgs: [{
- name: '',
- doc: "",
- type: _type1
- },
- ],
- inStream: null,
- outStream: null,
- tags: [canonicalize.reduce(new access.Tag("Read", true), new access.Tag()._type), ]
+ tags: [canonicalize.reduce(new access.Tag("Resolve", true), new access.Tag()._type), ]
},
diff --git a/src/gen-vdl/v.io/v23/services/syncbase/nosql/index.js b/src/gen-vdl/v.io/v23/services/syncbase/nosql/index.js
index a334d66..0e25715 100644
--- a/src/gen-vdl/v.io/v23/services/syncbase/nosql/index.js
+++ b/src/gen-vdl/v.io/v23/services/syncbase/nosql/index.js
@@ -299,7 +299,7 @@
DatabaseWatcher.prototype._serviceDescription = {
name: 'DatabaseWatcher',
pkgPath: 'v.io/v23/services/syncbase/nosql',
- doc: "// DatabaseWatcher allows a client to watch for updates to the database. For\n// each watch request, the client will receive a reliable stream of watch events\n// without re-ordering. See watch.GlobWatcher for a detailed explanation of the\n// behavior.\n// TODO(rogulenko): Currently the only supported watch patterns are\n// \"<tableName>/$/<rowPrefix>*\". Consider changing that.\n//\n// The watching is done by starting a streaming RPC. The argument to the RPC\n// contains the ResumeMarker that points to a particular place in the database\n// event log. The result stream consists of a never-ending sequence of Change\n// messages (until the call fails or is canceled). Each Change contains the Name\n// field in the form \"<tableName>/$/<rowKey>\" and the Value field of the\n// StoreChange type. If the client has no access to a row specified in a change,\n// that change is excluded from the result stream.\n//\n// DatabaseWatcher is designed to be used in the following way:\n// 1) begin a read-only batch\n// 2) read all data your app needs\n// 3) read the ResumeMarker\n// 4) abort the batch\n// 5) start watching for changes to the data using the ResumeMarker\n// In this configuration the client will not miss any changes to the data.",
+ doc: "// DatabaseWatcher allows a client to watch for updates to the database. For\n// each watch request, the client will receive a reliable stream of watch events\n// without re-ordering. See watch.GlobWatcher for a detailed explanation of the\n// behavior.\n// TODO(rogulenko): Currently the only supported watch patterns are\n// \"<tableName>/<rowPrefix>*\". Consider changing that.\n//\n// The watching is done by starting a streaming RPC. The argument to the RPC\n// contains the ResumeMarker that points to a particular place in the database\n// event log. The result stream consists of a never-ending sequence of Change\n// messages (until the call fails or is canceled). Each Change contains the Name\n// field in the form \"<tableName>/<rowKey>\" and the Value field of the\n// StoreChange type. If the client has no access to a row specified in a change,\n// that change is excluded from the result stream.\n//\n// DatabaseWatcher is designed to be used in the following way:\n// 1) begin a read-only batch\n// 2) read all data your app needs\n// 3) read the ResumeMarker\n// 4) abort the batch\n// 5) start watching for changes to the data using the ResumeMarker\n// In this configuration the client will not miss any changes to the data.",
embeds: [{
name: 'GlobWatcher',
pkgPath: 'v.io/v23/services/watch',
@@ -1147,7 +1147,7 @@
Database.prototype._serviceDescription = {
name: 'Database',
pkgPath: 'v.io/v23/services/syncbase/nosql',
- doc: "// Database represents a collection of Tables. Batches, queries, sync, watch,\n// etc. all operate at the Database level.\n// Database.Glob operates over Table names.\n// Param schemaVersion is the version number that the client expects the database\n// to be at. To disable schema version checking, pass -1.\n//\n// TODO(sadovsky): Add Watch method.",
+ doc: "// Database represents a collection of Tables. Batches, queries, sync, watch,\n// etc. all operate at the Database level.\n// Database.Glob operates over Table names.\n// Param schemaVersion is the version number that the client expects the\n// database to be at. To disable schema version checking, pass -1.",
embeds: [{
name: 'Object',
pkgPath: 'v.io/v23/services/permissions',
@@ -1156,7 +1156,7 @@
{
name: 'DatabaseWatcher',
pkgPath: 'v.io/v23/services/syncbase/nosql',
- doc: "// DatabaseWatcher allows a client to watch for updates to the database. For\n// each watch request, the client will receive a reliable stream of watch events\n// without re-ordering. See watch.GlobWatcher for a detailed explanation of the\n// behavior.\n// TODO(rogulenko): Currently the only supported watch patterns are\n// \"<tableName>/$/<rowPrefix>*\". Consider changing that.\n//\n// The watching is done by starting a streaming RPC. The argument to the RPC\n// contains the ResumeMarker that points to a particular place in the database\n// event log. The result stream consists of a never-ending sequence of Change\n// messages (until the call fails or is canceled). Each Change contains the Name\n// field in the form \"<tableName>/$/<rowKey>\" and the Value field of the\n// StoreChange type. If the client has no access to a row specified in a change,\n// that change is excluded from the result stream.\n//\n// DatabaseWatcher is designed to be used in the following way:\n// 1) begin a read-only batch\n// 2) read all data your app needs\n// 3) read the ResumeMarker\n// 4) abort the batch\n// 5) start watching for changes to the data using the ResumeMarker\n// In this configuration the client will not miss any changes to the data."
+ doc: "// DatabaseWatcher allows a client to watch for updates to the database. For\n// each watch request, the client will receive a reliable stream of watch events\n// without re-ordering. See watch.GlobWatcher for a detailed explanation of the\n// behavior.\n// TODO(rogulenko): Currently the only supported watch patterns are\n// \"<tableName>/<rowPrefix>*\". Consider changing that.\n//\n// The watching is done by starting a streaming RPC. The argument to the RPC\n// contains the ResumeMarker that points to a particular place in the database\n// event log. The result stream consists of a never-ending sequence of Change\n// messages (until the call fails or is canceled). Each Change contains the Name\n// field in the form \"<tableName>/<rowKey>\" and the Value field of the\n// StoreChange type. If the client has no access to a row specified in a change,\n// that change is excluded from the result stream.\n//\n// DatabaseWatcher is designed to be used in the following way:\n// 1) begin a read-only batch\n// 2) read all data your app needs\n// 3) read the ResumeMarker\n// 4) abort the batch\n// 5) start watching for changes to the data using the ResumeMarker\n// In this configuration the client will not miss any changes to the data."
},
{
name: 'SyncGroupManager',
@@ -1236,13 +1236,13 @@
],
inStream: null,
outStream: null,
- tags: [canonicalize.reduce(new access.Tag("Read", true), new access.Tag()._type), ]
+ tags: [canonicalize.reduce(new access.Tag("Resolve", true), new access.Tag()._type), ]
},
{
name: 'ListTables',
- doc: "// ListTables returns a list of all Table names.\n// TODO(sadovsky): Maybe switch to streaming RPC.",
+ doc: "// ListTables returns a list of all Table names.\n// This method exists on Database but not on Service or App because for the\n// latter we can simply use glob, while for the former glob fails on\n// BatchDatabase since we encode the batch id in the BatchDatabase object\n// name. More specifically, the glob client library appears to have two odd\n// behaviors:\n// 1) It checks Resolve access on every component along the path (by doing a\n// Dispatcher.Lookup), whereas this doesn't happen for other RPCs.\n// 2) It does a Glob(<prefix>/*) for every prefix path, and only proceeds to\n// the next path component if that component appeared in its parent's Glob\n// results. This is inefficient in general, and broken for us since\n// Glob(\"app/*\") does not return batch database names like \"a/d##bId\".\n// TODO(sadovsky): Maybe switch to streaming RPC.",
inArgs: [],
outArgs: [{
name: '',
@@ -1283,7 +1283,7 @@
{
name: 'BeginBatch',
- doc: "// BeginBatch creates a new batch. It returns an App-relative name for a\n// Database handle bound to this batch. If this Database is already bound to a\n// batch, BeginBatch() will fail with ErrBoundToBatch. Concurrency semantics\n// are documented in model.go.\n// TODO(sadovsky): Maybe make BatchOptions optional.",
+ doc: "// BeginBatch creates a new batch. It returns a \"batch suffix\" string to\n// append to the object name of this Database, yielding an object name for the\n// Database bound to the created batch. (For example, if this Database is\n// named \"/path/to/db\" and BeginBatch returns \"##abc\", the client should\n// construct batch Database object name \"/path/to/db##abc\".) If this Database\n// is already bound to a batch, BeginBatch() will fail with ErrBoundToBatch.\n// Concurrency semantics are documented in model.go.\n// TODO(sadovsky): Maybe make BatchOptions optional.",
inArgs: [{
name: 'schemaVersion',
doc: "",
@@ -1976,7 +1976,7 @@
],
inStream: null,
outStream: null,
- tags: [canonicalize.reduce(new access.Tag("Read", true), new access.Tag()._type), ]
+ tags: [canonicalize.reduce(new access.Tag("Resolve", true), new access.Tag()._type), ]
},
@@ -2191,7 +2191,7 @@
{
name: 'Exists',
- doc: "// Exists returns true only if this Row exists. Insufficient permissions\n// cause Exists to return false instead of an error.\n// TODO(ivanpi): Exists may fail with an error if higher levels of hierarchy\n// do not exist.",
+ doc: "// Exists returns true only if this Row exists. Insufficient permissions\n// cause Exists to return false instead of an error.\n// Note, Exists on Row requires read permissions, unlike higher levels of\n// hierarchy which require resolve, because Row existence usually carries\n// more information.\n// TODO(ivanpi): Exists may fail with an error if higher levels of hierarchy\n// do not exist.",
inArgs: [{
name: 'schemaVersion',
doc: "",
diff --git a/src/nosql/database.js b/src/nosql/database.js
index aef4454..4438831 100644
--- a/src/nosql/database.js
+++ b/src/nosql/database.js
@@ -185,7 +185,9 @@
* @param {function} cb Callback.
*/
Database.prototype.listTables = function(ctx, cb) {
- util.listChildren(ctx, this.fullName, 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);
};
/**
diff --git a/src/util.js b/src/util.js
index 0a1e52b..56aed63 100644
--- a/src/util.js
+++ b/src/util.js
@@ -137,9 +137,7 @@
* @return {string} Escaped string.
*/
function escape(s) {
- return s
- .replace(/%/g, '%25')
- .replace(/\//g, '%2F');
+ return vanadium.naming.encodeAsNameElement(s);
}
/**
@@ -149,5 +147,5 @@
* @return {string} Unescaped string.
*/
function unescape(s) {
- return decodeURIComponent(s);
+ return vanadium.naming.decodeFromNameElement(s);
}
diff --git a/test/integration/test-app.js b/test/integration/test-app.js
index ef2a68e..f7e5860 100644
--- a/test/integration/test-app.js
+++ b/test/integration/test-app.js
@@ -49,7 +49,9 @@
var appNames = [
uniqueName('app'),
uniqueName('app'),
- uniqueName('app')
+ uniqueName('app'),
+ uniqueName('app/b'), // symbols are okay
+ uniqueName('dev.v.io/a/admin@myapp.com'),
];
async.waterfall([
@@ -58,7 +60,7 @@
o.service.app(appName).exists(o.ctx, cb);
}),
function(existsArray, cb) {
- t.deepEqual(existsArray, [false, false, false],
+ t.deepEqual(existsArray, [false, false, false, false, false],
'exists: no apps exist');
cb(null);
},
@@ -81,7 +83,7 @@
o.service.app(appName).exists(o.ctx, cb);
}),
function(existsArray, cb) {
- t.deepEqual(existsArray, [true, true, true],
+ t.deepEqual(existsArray, [true, true, true, true, true],
'exists: all apps exist');
cb(null);
},
diff --git a/test/integration/test-table.js b/test/integration/test-table.js
index c82ede0..6e97b2a 100644
--- a/test/integration/test-table.js
+++ b/test/integration/test-table.js
@@ -16,7 +16,7 @@
// TODO(aghassemi): We fail to bind to Unicode names; investigate.
//var ROW_KEY = 'چשKEYઑᜰ';
//var ROW_VAL = '⛓⛸VALϦӪ';
-var ROW_KEY = 'row_key';
+var ROW_KEY = 'row_key/a^b'; // symbols are okay
var ROW_VAL = 'row value';
test('table.create() creates a table', function(t) {
@@ -346,8 +346,7 @@
});
}
-//TODO(aghassemi) Skipped test.
-//Set permission for prefix != "" is not implemented.
+// TODO(aghassemi) Enable this test.
test.skip('Getting/Setting permissions on rows', function(t) {
setupTable(t, function(err, o) {
if (err) {