<commit_before>/*!
 * Module dependencies.
 */

var _ = require('underscore'),
	keystone = require('../../'),
	util = require('util'),
	utils = require('keystone-utils'),
	super_ = require('../field');

/**
 * Relationship FieldType Constructor
 * @extends Field
 * @api public
 */

function relationship(list, path, options) {

	this.many = (options.many) ? true : false;
	this.filters = options.filters;
	this._nativeType = keystone.mongoose.Schema.Types.ObjectId;
	this._underscoreMethods = ['format'];

	relationship.super_.call(this, list, path, options);

}

/*!
 * Inherit from Field
 */

util.inherits(relationship, super_);


/**
 * Registers the field on the List's Mongoose Schema.
 *
 * @api public
 */

relationship.prototype.addToSchema = function() {

	var field = this,
		schema = this.list.schema;

	this.paths = {
		refList: this.options.refListPath || this._path.append('RefList')
	};

	var def = {
		type: this._nativeType,
		ref: this.options.ref
	};

	schema.path(this.path, this.many ? [def] : def);

	schema.virtual(this.paths.refList).get(function () {
		return keystone.list(field.options.ref);
	});

	if (this.many) {
		this.underscoreMethod('contains', function(find) {
			var value = this.populated(field.path) || this.get(field.path);
			if ('object' === typeof find) {
				find = find.id;
			}
			var result = _.some(value, function(value) {
				return (value + '' === find);
			});
			return result;
		});
	}

	this.bindUnderscoreMethods();

};

/**
 * Formats the field value
 *
 * @api public
 */
relationship.prototype.format = function(item) {
	var value = item.get(this.path);
	// force the formatted value to be a - unexpected things happen with ObjectIds.
	return this.many ? value.join(', ') : (value || '') + '';
};


/**
 * Validates that a value for this field has been provided in a data object
 *
 * @api public
 */

relationship.prototype.validateInput = function(data, required, item) {

	if (!required) return true;
	if (!(this.path in data) && item && ((this.many && item.get(this.path).length) || item.get(this.path))) return true;

	if ('string' === typeof data[this.path]) {
		return (data[this.path].trim()) ? true : false;
	} else {
		return (data[this.path]) ? true : false;
	}

};


/**
 * Updates the value for this field in the item from a data object.
 * Only updates the value if it has changed.
 * Treats an empty string as a null value.
 *
 * @api public
 */

relationship.prototype.updateItem = function(item, data) {

	if (!(this.path in data)) {
		return;
	}

	if (item.populated(this.path)) {
		throw new Error('fieldTypes.relationship.updateItem() Error - You cannot update populated relationships.');
	}

	if (this.many) {

		var arr = item.get(this.path),
			_old = arr.map(function(i) { return String(i); }),
			_new = data[this.path];

		if (!utils.isArray(_new)) {
			_new = String(_new || '').split(',');
		}

		_new = _.compact(_new);

		// remove ids
		_.difference(_old, _new).forEach(function(val) {
			arr.pull(val);
		});
		// add new ids
		_.difference(_new, _old).forEach(function(val) {
			arr.push(val);
		});

	} else {
		if (data[this.path]) {
			if (data[this.path] != item.get(this.path)) {
				item.set(this.path, data[this.path]);
			}
		} else if (item.get(this.path)) {
			item.set(this.path, null);
		}
	}

};


/**
 * Returns true if the relationship configuration is valid
 *
 * @api public
 */

Object.defineProperty(relationship.prototype, 'isValid', {
	get: function() {
		return keystone.list(this.options.ref) ? true : false;
	}
});


/**
 * Returns the Related List
 *
 * @api public
 */<commit_msg>Improved relationship.js based on linter<commit_after>/*!
 * Module dependencies.
 */

var _ = require('underscore'),
	keystone = require('../../'),
	util = require('util'),
	utils = require('keystone-utils'),
	super_ = require('../field');

/**
 * Relationship FieldType Constructor
 * @extends Field
 * @api public
 */

function relationship(list, path, options) {

	this.many = (options.many) ? true : false;
	this.filters = options.filters;
	this._nativeType = keystone.mongoose.Schema.Types.ObjectId;
	this._underscoreMethods = ['format'];

	relationship.super_.call(this, list, path, options);

}

/*!
 * Inherit from Field
 */

util.inherits(relationship, super_);


/**
 * Registers the field on the List's Mongoose Schema.
 *
 * @api public
 */

relationship.prototype.addToSchema = function() {

	var field = this,
		schema = this.list.schema;

	this.paths = {
		refList: this.options.refListPath || this._path.append('RefList')
	};

	var def = {
		type: this._nativeType,
		ref: this.options.ref
	};

	schema.path(this.path, this.many ? [def] : def);

	schema.virtual(this.paths.refList).get(function () {
		return keystone.list(field.options.ref);
	});

	if (this.many) {
		this.underscoreMethod('contains', function(find) {
			var value = this.populated(field.path) || this.get(field.path);
			if ('object' === typeof find) {
				find = find.id;
			}
			var result = _.some(value, function(value) {
				return (value + '' === find);
			});
			return result;
		});
	}

	this.bindUnderscoreMethods();

};

/**
 * Formats the field value
 *
 * @api public
 */
relationship.prototype.format = function(item) {
	var value = item.get(this.path);
	// force the formatted value to be a - unexpected things happen with ObjectIds.
	return this.many ? value.join(', ') : (value || '') + '';
};


/**
 * Validates that a value for this field has been provided in a data object
 *
 * @api public
 */

relationship.prototype.validateInput = function(data, required, item) {

	if (!required) return true;
	if (!(this.path in data) && item && ((this.many && item.get(this.path).length) || item.get(this.path))) return true;

	if ('string' === typeof data[this.path]) {
		return (data[this.path].trim()) ? true : false;
	} else {
		return (data[this.path]) ? true : false;
	}

};


/**
 * Updates the value for this field in the item from a data object.
 * Only updates the value if it has changed.
 * Treats an empty string as a null value.
 *
 * @api public
 */

relationship.prototype.updateItem = function(item, data) {

	if (!(this.path in data)) {
		return;
	}

	if (item.populated(this.path)) {
		throw new Error('fieldTypes.relationship.updateItem() Error - You cannot update populated relationships.');
	}

	if (this.many) {

		var arr = item.get(this.path),
			_old = arr.map(function(i) { return String(i); }),
			_new = data[this.path];

		if (!utils.isArray(_new)) {
			_new = String(_new || '').split(',');
		}

		_new = _.compact(_new);

		// remove ids
		_.difference(_old, _new).forEach(function(val) {
			arr.pull(val);
		});
		// add new ids
		_.difference(_new, _old).forEach(function(val) {
			arr.push(val);
		});

	} else {
		if (data[this.path]) {
			if (data[this.path] !== item.get(this.path)) {
				item.set(this.path, data[this.path]);
			}
		} else if (item.get(this.path)) {
			item.set(this.path, null);
		}
	}

};


/**
 * Returns true if the relationship configuration is valid
 *
 * @api public
 */

Object.defineProperty(relationship.prototype, 'isValid', {
	get: function() {
		return keystone.list(this.options.ref) ? true : false;
	}
});


/**
 * Returns the Related List
 *
 * @api public
 */
{'fraction_non_alphanumeric': 0.17077221145862165, 'fraction_numerical': 0.0, 'mean_word_length': 3.444649446494465, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7564222', 'n_tokens_mistral': 2604, 'n_tokens_neox': 2394, 'n_words': 588}