# 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
    1081×
    1×

    1×

    2×
    2×
    2×

    2×

    2×

    2×
    2×

    2×
    2×
    2×

    2×

    2×
    2×

    2×

    2×

    16×

    16×

    16×
    16×

    16×

    16×
    16×

    2×

    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();
    		}

    	});

    };