all files / keystone/lib/schemaPlugins/ autokey.js

63.79% Statements 37/58
34.88% Branches 15/43
85.71% Functions 6/7
63.79% Lines 37/58
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108                                             16×   16×                   16× 16×     16×                   16× 16×           16× 16×   16× 16× 16× 16× 16×                       16×     16× 16× 16×                  
var _ = require('lodash');
var utils = require('keystone-utils');
 
module.exports = function autokey () {
 
	var autokey = this.autokey = _.clone(this.get('autokey'));
	var def = {};
	var list = this;
 
	Iif (!autokey.from) {
		var fromMsg = 'Invalid List Option (autokey) for ' + list.key + ' (from is required)\n';
		throw new Error(fromMsg);
	}
	Iif (!autokey.path) {
		var pathMsg = 'Invalid List Option (autokey) for ' + list.key + ' (path is required)\n';
		throw new Error(pathMsg);
	}
 
	Eif (typeof autokey.from === 'string') {
		autokey.from = autokey.from.split(' ');
	}
 
	autokey.from = autokey.from.map(function (i) {
		i = i.split(':');
		return { path: i[0], format: i[1] };
	});
 
	def[autokey.path] = {
		type: String,
		index: true,
	};
 
	Eif (autokey.unique) {
		def[autokey.path].index = { unique: true };
	}
 
	this.schema.add(def);
 
	var getUniqueKey = function (doc, src, callback) {
 
		var q = list.model.find().where(autokey.path, src);
 
		Iif (_.isObject(autokey.unique)) {
			_.forEach(autokey.unique, function (k, v) {
				if (_.isString(v) && v.charAt(0) === ':') {
					q.where(k, doc.get(v.substr(1)));
				} else {
					q.where(k, v);
				}
			});
		}
 
		q.exec(function (err, results) {
			Iif (err) {
				callback(err);
			// deliberate use of implicit type coercion with == because doc.id may need to become a String
			} else Iif (results.length && (results.length > 1 || results[0].id != doc.id)) { // eslint-disable-line eqeqeq
				var inc = src.match(/^(.+)\-(\d+)$/);
				if (inc && inc.length === 3) {
					src = inc[1];
					inc = '-' + ((inc[2] * 1) + 1);
				} else {
					inc = '-1';
				}
				return getUniqueKey(doc, src + inc, callback);
			} else {
				doc.set(autokey.path, src);
				return callback();
			}
		});
	};
 
	this.schema.pre('save', function (next) {
 
		var modified = false;
		var values = [];
 
		autokey.from.forEach(function (ops) {
			Eif (list.fields[ops.path]) {
				values.push(list.fields[ops.path].format(this, ops.format));
				Eif (list.fields[ops.path].isModified(this)) {
					modified = true;
				}
			} else {
				values.push(this.get(ops.path));
				// virtual paths are always assumed to have changed, except 'id'
				if (ops.path !== 'id' && list.schema.pathType(ops.path) === 'virtual' || this.isModified(ops.path)) {
					modified = true;
				}
			}
		}, this);
 
		// if has a value and is unmodified or fixed, don't update it
		Iif ((!modified || autokey.fixed) && this.get(autokey.path)) {
			return next();
		}
		var newKey = utils.slug(values.join(' '), null, { locale: autokey.locale }) || this.id;
		Eif (autokey.unique) {
			return getUniqueKey(this, newKey, next);
		} else {
			this.set(autokey.path, newKey);
			return next();
		}
 
	});
 
};