Skip to content

Commit

Permalink
Merge pull request #476 from coralproject/metadata
Browse files Browse the repository at this point in the history
MetadataService
  • Loading branch information
jde authored Apr 12, 2017
2 parents 3e88245 + c7e1943 commit b3ce450
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 1 deletion.
8 changes: 8 additions & 0 deletions graph/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const {
GraphQLInterfaceType
} = require('graphql');
const debug = require('debug')('talk:graph:schema');
const Joi = require('joi');

/**
* XXX taken from graphql-js: src/execution/execute.js, because that function
Expand Down Expand Up @@ -82,6 +83,8 @@ const decorateWithHooks = (schema, hooks) => forEachField(schema, (field, typeNa
Object.keys(hooks).forEach((hook) => {
switch (hook) {
case 'pre':
Joi.assert(hooks.pre, Joi.func().maxArity(4));

debug(`adding pre hook to resolver ${typeName}.${fieldName} from plugin '${plugin.name}'`);

if (typeof hooks.pre !== 'function') {
Expand All @@ -91,6 +94,8 @@ const decorateWithHooks = (schema, hooks) => forEachField(schema, (field, typeNa
acc.pre.push(hooks.pre);
break;
case 'post':
Joi.assert(hooks.pre, Joi.func().maxArity(5));

debug(`adding post hook to resolver ${typeName}.${fieldName} from plugin '${plugin.name}'`);

if (typeof hooks.post !== 'function') {
Expand Down Expand Up @@ -129,6 +134,9 @@ const decorateWithHooks = (schema, hooks) => forEachField(schema, (field, typeNa
return;
}

// Ensure it matches the format we expect.
Joi.assert(post, Joi.array().items(Joi.func().maxArity(3)), `invalid post hooks were found for ${typeName}.${fieldName}`);

// Cache the original resolverType function.
let resolveType = field.resolveType;

Expand Down
6 changes: 6 additions & 0 deletions models/asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ const AssetSchema = new Schema({
type: Schema.Types.Mixed,
default: null
},

// Additional metadata stored on the field.
metadata: {
default: {},
type: Object
}
}, {
versionKey: false,
timestamps: {
Expand Down
8 changes: 7 additions & 1 deletion models/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,13 @@ const CommentSchema = new Schema({
default: 'NONE'
},
tags: [TagSchema],
parent_id: String
parent_id: String,

// Additional metadata stored on the field.
metadata: {
default: {},
type: Object
}
}, {
timestamps: {
createdAt: 'created_at',
Expand Down
80 changes: 80 additions & 0 deletions services/metadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* The key must be composed of alpha characters with periods seperating them.
*/
const KEY_REGEX = /^(?:[A-Za-z][A-Za-z\.]*[A-Za-z])?(?:[A-Za-z]*)$/;

/**
* Allows metadata properties to be set/unset from specific models. It is the
* expecatation of this API that the metadata field is either accessed later
* directly, or accessed as a result of another database load rather than
* this service providing an interface to do so.
*
* @class MetadataService
*/
class MetadataService {

/**
* Parses a key by ensuring that if it is either a string, or an array with
* only characters defined in the `KEY_REGEX`
*
* @static
* @param {String|Array} key
* @returns {String} string form of the key
*
* @memberOf Metadata
*/
static parseKey(key) {
if (Array.isArray(key)) {
key = key.join('.');
}

if ((typeof key !== 'string') || !KEY_REGEX.test(key) || key.length === 0) {
throw new Error(`${key} is not valid, only a-zA-Z. allowed`);
}

return ['metadata', key].join('.');
}

/**
* Sets an object on the metadata field of an object.
*
* @static
* @param {mongoose.Model} model the mongoose model for the object
* @param {String} id the value for the field `id` of the model
* @param {String|Array} key key for the metadata field
* @param {any} value javascript object to set the value of the metadata to
* @returns {Promise} resolves when the update is complete
*
* @memberOf Metadata
*/
static async set(model, id, key, value) {
key = MetadataService.parseKey(key);

return model.update({id}, {
$set: {
[key]: value
}
});
}

/**
* Removes the value for the metadata field as the specific key.
*
* @static
* @param {mongoose.Model} model the mongoose model for the object
* @param {String} id the value for the field `id` of the model
* @param {String|Array} key key for the metadata field
* @returns
*
* @memberOf Metadata
*/
static async unset(model, id, key) {
key = MetadataService.parseKey(key);

return model.update({id}, {
$unset: {[key]: ''}
});
}
}

module.exports = MetadataService;

0 comments on commit b3ce450

Please sign in to comment.