-
Notifications
You must be signed in to change notification settings - Fork 596
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
125 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
var entityMeta = {}; | ||
|
||
var namespaceRegex = kindRegex = fieldNameRegex = new RegExp(/^[A-Za-z]+$/); | ||
|
||
/** | ||
* Registers a kind and its field meta globally. In order | ||
* to perform CRUD operations for a kind, you should register | ||
* it with its field metadata. | ||
* | ||
* registerKind('namespace', 'Author', { | ||
* name: { kind: STRING, indexed: false }, | ||
* tags: { kind: STRING, multi: true }, // an array of string elements. | ||
* favArticles: { kind: KEY, multi: true } | ||
* contact: { | ||
* kind: { | ||
* telephone: { kind: String }, | ||
* email: { kind: String } | ||
* } | ||
* } | ||
* }); | ||
* | ||
* @param {string} namespace Namespace of the kind. | ||
* @param {string} kind Name of the kind. | ||
* @param {object} fieldMeta Object that contains metadata information | ||
* about the fields. | ||
*/ | ||
function registerKind(namespace, kind, fieldMeta) { | ||
// validate the input and put it to the dictionary | ||
namespace = namespace || 'default'; | ||
if (!namespaceRegex.test(namespace)) { | ||
throw new Error('Namespaces should match ' + namespaceRegex); | ||
} | ||
if (!kindRegex.test(kind)) { | ||
throw new Error('Kinds should match ' + kindRegex); | ||
} | ||
|
||
// TODO(jbd): Validate namespace, kind and fieldMeta. | ||
Object.keys(fieldMeta).forEach(function (fieldName) { | ||
validateField(fieldName, fieldMeta[fieldName]); | ||
}); | ||
|
||
if (!entityMeta[namespace]) { | ||
entityMeta[namespace] = {}; | ||
} | ||
entityMeta[namespace][kind] = fieldMeta; | ||
} | ||
|
||
function getKind(namespace, kind) { | ||
return entityMeta[namespace] && entityMeta[namespace][kind]; | ||
}; | ||
|
||
function validateField(name, field) { | ||
if (!fieldNameRegex.test(name)) { | ||
throw new Error('Field name should match ' + fieldNameRegex); | ||
} | ||
if (!field.kind) { | ||
throw new Error('Provide a kind for field ' + name); | ||
} | ||
if (typeof field.kind != 'object' && !primitiveKinds[field.kind]) { | ||
throw new Error('Unknown kind for field ' + name); | ||
} | ||
if (typeof field.kind == 'object') { | ||
Object.keys(field.key).forEach(function (key) { | ||
validateField(key, field.key[key]); | ||
}); | ||
} | ||
} | ||
|
||
var primitiveKinds = { | ||
BOOL: 'BOOL', | ||
NUMBER: 'NUMBER', | ||
STRING: 'STRING', | ||
BYTES: 'BYTES', | ||
DATETIME: 'DATETIME', | ||
KEY: 'KEY' | ||
} | ||
|
||
/** | ||
* Export primitive kinds. | ||
*/ | ||
module.exports.kinds = primitiveKinds; | ||
|
||
/** | ||
* Export registerKind. | ||
* @type {function} | ||
*/ | ||
module.exports.registerKind = registerKind; | ||
|
||
/** | ||
* Exports getKind. | ||
* @type {function} | ||
*/ | ||
module.exports.getKind = getKind; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
var assert = require('assert'), | ||
entity = require('../lib/datastore/entity.js'); | ||
|
||
var blogPostMetadata = { | ||
title: { kind: entity.kinds.STRING, indexed: true }, | ||
tags: { kind: entity.kinds.STRING, multi: true, indexed: true }, | ||
publishedAt: { kind: entity.kinds.DATETIME }, | ||
author: { kind: entity.kinds.KEY, indexed: true }, | ||
isDraft: { kind: entity.kinds.BOOL, indexed: true } | ||
} | ||
|
||
describe('registerKind', function() { | ||
|
||
it('should be able to register valid field metadata', function(done) { | ||
entity.registerKind('namespace', 'kind', blogPostMetadata); | ||
done(); | ||
}); | ||
|
||
it('should set the namespace to be "default" if zero value or null is provided', function(done) { | ||
entity.registerKind(null, 'kind', blogPostMetadata); | ||
var meta = entity.getKind('default', 'kind'); | ||
assert.strictEqual(meta, blogPostMetadata); | ||
done(); | ||
}); | ||
|
||
it('should throw an exception if an invalid kind is provided', function(done) { | ||
assert.throws(function() { | ||
entity.registerKind(null, '000', blogPostMetadata); | ||
}, /Kinds should match/); | ||
done(); | ||
}); | ||
}); |