diff --git a/models/asset.js b/models/asset.js index f0046aef0..51ff42705 100644 --- a/models/asset.js +++ b/models/asset.js @@ -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: { diff --git a/models/comment.js b/models/comment.js index e6523e45f..0984a0832 100644 --- a/models/comment.js +++ b/models/comment.js @@ -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', diff --git a/services/metadata.js b/services/metadata.js new file mode 100644 index 000000000..a0c433f8b --- /dev/null +++ b/services/metadata.js @@ -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;