jii-model
Version:
1,412 lines (1,221 loc) • 35.9 kB
JavaScript
/**
* @author <a href="http://www.affka.ru">Vladimir Kozhin</a>
* @license MIT
*/
'use strict';
var Jii = require('jii');
var InvalidParamException = require('jii/exceptions/InvalidParamException');
var CollectionEvent = require('../model/CollectionEvent');
var InvalidConfigException = require('jii/exceptions/InvalidConfigException');
var NotSupportedException = require('jii/exceptions/NotSupportedException');
var _isArray = require('lodash/isArray');
var _isObject = require('lodash/isObject');
var _isFunction = require('lodash/isFunction');
var _isString = require('lodash/isString');
var _indexOf = require('lodash/indexOf');
var _toArray = require('lodash/toArray');
var _reduceRight = require('lodash/reduceRight');
var _groupBy = require('lodash/groupBy');
var _countBy = require('lodash/countBy');
var _lastIndexOf = require('lodash/lastIndexOf');
var _findIndex = require('lodash/findIndex');
var _findLastIndex = require('lodash/findLastIndex');
var _has = require('lodash/has');
var _each = require('lodash/each');
var _map = require('lodash/map');
var _filter = require('lodash/filter');
var _reduce = require('lodash/reduce');
var _find = require('lodash/find');
var _reject = require('lodash/reject');
var _every = require('lodash/every');
var _some = require('lodash/some');
var _maxBy = require('lodash/maxBy');
var _minBy = require('lodash/minBy');
var _first = require('lodash/first');
var _initial = require('lodash/initial');
var _last = require('lodash/last');
var _drop = require('lodash/drop');
var _shuffle = require('lodash/shuffle');
var _sortBy = require('lodash/sortBy');
var _without = require('lodash/without');
var _extend = require('lodash/extend');
var Component = require('jii/base/Component');
/**
* BaseCollection provides a base class that implements the [[CollectionInterface]].
*
* @class Jii.base.Collection
* @extends Jii.base.Component
* @extends Array
*/
var Collection = Jii.defineClass('Jii.base.Collection', /** @lends Jii.base.Collection.prototype */{
__extends: Component,
__static: /** @lends Jii.base.Collection */{
/**
* @event Jii.base.Collection#add
* @property {Jii.model.CollectionEvent} event
*/
EVENT_ADD: 'add',
/**
* @event Jii.base.Collection#fetched
* @property {Jii.model.CollectionEvent} event
*/
EVENT_FETCHED: 'fetched',
/**
* @event Jii.base.Collection#change
* @property {Jii.model.CollectionEvent} event
*/
EVENT_CHANGE: 'change',
/**
* @event Jii.base.Collection#change:
* @property {Jii.model.CollectionEvent} event
*/
EVENT_CHANGE_NAME: 'change:',
/**
* @event Jii.base.Collection#remove
* @property {Jii.model.CollectionEvent} event
*/
EVENT_REMOVE: 'remove'
},
/**
* @type {number}
*/
length: 0,
/**
* @type {string|Jii.base.Model}
*/
modelClass: null,
/**
* Root collection
* @type {Jii.base.Collection}
*/
parent: null,
/**
* @type {boolean}
*/
_isFetched: false,
_byId: {},
_filter: null,
_eventsChangeName: [],
_editedLevel: 0,
_childCollections: [],
_editedEvents: [],
/**
* @param {[]|object} [models]
* @param {object} [config]
* @constructor
*/
constructor(models, config) {
this.__super(config);
if (_isArray(models)) {
this.add(models);
}
},
/**
* @returns {[]|object}
*/
getModels() {
return this.map(model => model);
},
/**
*
* @param {object|object[]|Jii.base.Model|Jii.base.Model[]} models
*/
setModels(models) {
if (!_isArray(models)) {
models = [models];
}
if (this.parent) {
this.parent.setModels(models);
} else {
this._change(this.length, models, [], true);
}
},
/**
*
* @param {object|object[]|Jii.base.Model|Jii.base.Model[]} models
* @param {number} [index]
* @returns {Jii.base.Model[]}
*/
add(models, index) {
if (!_isArray(models)) {
models = [models];
}
if (this.parent) {
this.parent.add(models, index);
} else {
if (!index && index !== 0) {
index = this.length;
}
return this._change(index, models, []).added;
}
},
/**
*
* @param {*|*[]} models
* @returns {Jii.base.Model[]}
*/
remove(models) {
if (!_isArray(models)) {
models = [models];
}
if (this.parent) {
this.parent.remove(models);
} else {
return this._change(0, [], models).removed;
}
},
/**
*
* @param {string|object|object[]} name
* @param {*} [value]
* @returns {*}
*/
set(name, value) {
// Format [0].name
var indexFormat = this._detectKeyFormatIndex(name);
if (indexFormat) {
var model = this.at(indexFormat.index);
if (model) {
return model.set(indexFormat.subName, value);
}
throw new InvalidParamException('Not found model with index `' + indexFormat.index + '` for set attribute `' + indexFormat.subName + '`.');
}
// Object format
if (_isObject(name) && !_has(name, 'modelClass')) {
return this.setModels(name);
}
// Array format
if (_isArray(name)) {
return this.setModels(name);
}
return this.__super(name, value);
},
/**
*
* @param {string} name
* @returns {*}
*/
get(name) {
// Format [0].name
var indexFormat = this._detectKeyFormatIndex(name);
if (indexFormat) {
var model = this.at(indexFormat.index);
if (model) {
return indexFormat.subName ? model.get(indexFormat.subName) : model;
}
return null;
}
// Get by pk
var primaryKey = this._getPrimaryKey(name);
if (_has(this._byId, primaryKey)) {
return this._byId[primaryKey];
}
return this.__super(name);
},
getRoot() {
var parent = this;
while (true) {
if (!parent.parent) {
return parent;
}
parent = parent.parent;
}
},
/**
*
* @param {function|Jii.base.Query} value
*/
setFilter(value) {
// @todo normalize code, remove duplicates
var modelClass = this.modelClass && Jii.namespace(this.modelClass);
var db = modelClass && modelClass.getDb && modelClass.getDb();
var parentCollection = this.parent || this;
// Function
if (_isFunction(value) || value === null) {
if (!this._filter || this._filter !== value) {
// Unsubscribe previous
if (db && this._filter && this._filter.query && this._filter.attributes) {
_each(this._filter.attributes, attribute => {
parentCollection.off(this.__static.EVENT_CHANGE_NAME + attribute, {
context: this,
callback: this.refreshFilter
});
});
}
this._filter = value;
this.refreshFilter();
}
}
// Query instance
// TODO Instance of without require deps
if (_isObject(value) && _isFunction(value.createCommand) && _isFunction(value.prepare) && (!this._filter || this._filter.query !== value)) {
if (db) {
// Unsubscribe previous
if (this._filter && this._filter.query && this._filter.attributes) {
_each(this._filter.attributes, attribute => {
parentCollection.off(this.__static.EVENT_CHANGE_NAME + attribute, {
context: this,
callback: this.refreshFilter
});
});
}
}
this._filter = this._normalizePredicate(value);
if (db) {
// Subscribe current
_each(this._filter.attributes, attribute => {
parentCollection.on(this.__static.EVENT_CHANGE_NAME + attribute, {
context: this,
callback: this.refreshFilter
});
});
}
this.refreshFilter();
}
},
/**
* Run filter
*/
refreshFilter() {
var models = this._filterModels();
var diff = this._prepareDiff(models);
if (diff.add.length || diff.remove.length) {
this._change(0, diff.add, diff.remove, true);
}
_each(this._childCollections, childCollection => {
childCollection.refreshFilter();
});
},
_filterModels() {
var models = this.parent ? this.parent.getModels() : this.getModels();
if (this._filter) {
// Optimize search by id
// @todo bad condition.. =(
var where = this._filter.query ? this._filter.query.getWhere() : null;
if (_isArray(where)
&& _isString(where[0])
&& where[0].toLowerCase() === 'in'
&& where[1].toString() === Jii.namespace(this.modelClass).primaryKey().toString()) {
models = _map(where[2], id => this._byId[id]);
} else {
models = _filter(models, this._filter);
}
}
return models;
},
/**
* @return {boolean}
*/
isFetched() {
return this._isFetched;
},
/**
*
* @param {object|Jii.base.CollectionAdapterInterface} collectionAdapter
*/
createProxy(collectionAdapter) {
var cloned = collectionAdapter.instance(this);
// Fill
collectionAdapter.add(this, cloned, this.getModels());
// Subscribe
this.on(
this.__static.EVENT_CHANGE,
/** @param {Jii.model.CollectionEvent} event */
event => {
if (event.added.length > 0) {
collectionAdapter.add(this, cloned, event.added);
}
if (event.removed.length > 0) {
collectionAdapter.remove(this, cloned, event.removed);
}
}
);
return cloned;
},
/**
* Begin change operation
*/
beginEdit() {
this._editedLevel++;
_each(this._childCollections, childCollection => {
childCollection.beginEdit();
});
},
/**
* Cancel all changes after beginEdit() call
*/
cancelEdit() {
if (this._editedLevel > 0) {
this._editedLevel--;
}
// Cancel in sub-models
if (this._editedLevel === 0) {
_each(this._childCollections, childCollection => {
childCollection.cancelEdit();
});
// Revert changes
// TODO
// Reset state
this._editedEvents = [];
}
},
/**
* End change operation - trigger change events
*/
endEdit() {
if (this._editedLevel > 0) {
this._editedLevel--;
}
if (this._editedLevel === 0) {
// End in child
_each(this._childCollections, childCollection => {
childCollection.endEdit();
});
// Each trigger events in children
_each(this._editedEvents,
/** @param {Jii.model.CollectionEvent} event */
event => {
if (event.added.length > 0) {
this.trigger(this.__static.EVENT_ADD, event);
}
if (event.isFetch) {
this.trigger(this.__static.EVENT_FETCHED, event);
}
if (event.removed.length > 0) {
this.trigger(this.__static.EVENT_REMOVE, event);
}
if (event.added.length > 0 || event.removed.length > 0) {
this.trigger(this.__static.EVENT_CHANGE, event);
}
if (event.isSorted) {
this._onSort();
}
});
// Reset state
this._editedEvents = [];
}
},
/**
*
*
* @param {number|string|object} primaryKey
* @returns {*|null}
*/
getById(primaryKey) {
return this._byId[this._getPrimaryKey(primaryKey)] || null;
},
/**
*
* @returns {number}
*/
getCount() {
return this.length;
},
/**
*
* @returns {[]}
*/
getKeys() {
return this.map(this._getPrimaryKey.bind(this));
},
/**
* @param options
* @returns {*}
*/
toJSON(options) {
return this.map(model => model.toJSON(options));
},
/**
*
* @param {number} index
* @returns {*}
*/
at(index) {
if (index < 0) {
index = Math.max(0, this.length + index);
}
return this[index] || null;
},
/**
*
* @param {*} [models]
*/
reset(models) {
models = models || [];
if (!_isArray(models)) {
models = [models];
}
if (this.parent) {
this.parent.reset(models);
} else {
var diff = this._prepareDiff(models);
this._change(0, diff.add, diff.remove, true);
}
},
_prepareDiff(models) {
var toAdd = [];
_each(models, data => {
var finedModels = this._findModels(data);
if (finedModels.length) {
// Convert data to model
_each(this._findModels(data), model => {
if (_indexOf(toAdd, model) === -1) {
toAdd.push(model);
}
});
} else {
toAdd.push(data);
}
});
var toRemove = [];
_each(this.getModels(), model => {
if (_indexOf(toAdd, model) === -1) {
toRemove.push(model);
}
});
return {
add: toAdd,
remove: toRemove
};
},
/**
*
* @returns {static}
*/
clone() {
return new this.__static(this.getModels(), {
modelClass: this.modelClass
});
},
/**
*
* @param {function|Jii.base.Query} [filter]
* @param {object} [params]
* @param {Jii.base.Collection} [className]
* @returns {Jii.base.Collection}
*/
createChild(filter = null, params = {}, className = null) {
className = className || this.__static;
var models = params.models || null;
delete params.models;
var childCollection = new className(null, _extend({}, params, {
modelClass: this.modelClass,
parent: this
}));
if (this._isFetched) {
childCollection._change(0, this.getModels(), [], true);
}
this._childCollections.push(childCollection);
if (models) {
childCollection.setModels(models);
}
if (filter) {
childCollection.setFilter(filter);
}
return childCollection;
},
/**
*
* @param {object} [params]
* @param {Jii.base.DataProvider} [className]
* @returns {Jii.base.Collection}
*/
createDataProvider(params = {}, className = null) {
className = className || require('./DataProvider');
return this.createChild(null, params, className);
},
/**
*
* @param name
* @returns {{index: number, subName: string|null}}
* @private
*/
_detectKeyFormatIndex(name) {
var matches = /^\[([0-9]+)\]\.?(.*)/.exec(name);
if (matches === null) {
return null;
}
return {
index: parseInt(matches[1]),
subName: matches[2] || null
};
},
_change(startIndex, toAdd, toRemove, unique, byParent) {
unique = unique || false;
byParent = byParent || false;
var isFirstUpdate = !this.isFetched();
// Mark as fetched on any adds
this._isFetched = true;
var added = [];
var removed = [];
// Remove
_each(toRemove, data => {
_each(this._findModels(data), model => {
var index = this.indexOf(model);
if (index < startIndex) {
startIndex--;
}
if (this._remove(model, index)) {
removed.push(model);
}
});
});
// Add
_each(toAdd, data => {
var existsModels = unique ? this._findModels(data) : [];
var models = existsModels.length > 0 ? existsModels : [this.createModel(data)];
if (this._filter) {
models = _filter(models, this._filter, this);
}
_each(models, model => {
// Check moving
if (existsModels.length > 0) {
// Update model attributes
var Model = require('./Model');
if (model instanceof Model && _isObject(data) && !(data instanceof Model)) {
model.set(data);
}
} else if (this._add(model, startIndex)) {
added.push(model);
startIndex++;
}
});
});
// Lazy subscribe on added
_each(added, model => {
_each(this._eventsChangeName, arr => {
model.on.apply(model, arr);
});
});
// Unsubscribe on removed
_each(removed, model => {
_each(this._eventsChangeName, arr => {
model.off.apply(model, arr.slice(0, 2));
});
});
// Start
this.beginEdit();
// Trigger events
this._editedEvents.push(this._createEvent({
isFetch: isFirstUpdate,
added: added,
removed: removed
}));
// Change children
_each(this._childCollections, childCollection => {
childCollection._change(startIndex, added, removed, true, {
startIndex: startIndex,
toAdd: toAdd,
toRemove: toRemove,
unique: unique,
});
});
// End
this.endEdit();
return {
added: added,
removed: removed
};
},
_add(model, index) {
// Array access
Array.prototype.splice.call(this, index++, 0, model);
// By id
var ActiveRecord = require('./BaseActiveRecord');
if (model instanceof ActiveRecord) {
this._byId[this._getPrimaryKey(model)] = model;
}
return true;
},
_remove(model, index) {
// Array access
Array.prototype.splice.call(this, index, 1);
// By id
var ActiveRecord = require('./BaseActiveRecord');
if (model instanceof ActiveRecord) {
delete this._byId[this._getPrimaryKey(model)];
}
return true;
},
/**
*
* @param {object} params
* @returns {Jii.model.CollectionEvent}
*/
_createEvent(params) {
return new CollectionEvent(params);
},
/**
*
* @param {number|string|object} data
* @returns {*|*[]}
* @private
*/
_findModels(data) {
var primaryKey = this._getPrimaryKey(data);
if (this.modelClass) {
return this._byId[primaryKey] ? [this._byId[primaryKey]] : [];
} else {
return this.filter(model => primaryKey == this._getPrimaryKey(model));
}
},
/**
*
* @param {number|string|object} data
* @returns {string}
*/
_getPrimaryKey(data) {
var ActiveRecord = require('./BaseActiveRecord');
if (_isObject(data) && this.modelClass && !(data instanceof ActiveRecord)) {
let keys = this.modelClass.primaryKey();
if (keys.length === 1) {
data = data[keys[0]];
} else {
let obj = {};
this.modelClass.primaryKey().forEach(attribute => {
obj[attribute] = _has(data, attribute) ? data[attribute] : null;
});
data = obj;
}
}
if (data instanceof ActiveRecord) {
data = data.getPrimaryKey();
}
if (_isObject(data)) {
return JSON.stringify(data);
}
return data;
},
/**
* Convert any data to model
* @param {object|*} [data]
* @returns {Jii.base.Model}
*/
createModel(data) {
// Already model
var Model = require('./Model');
if (data instanceof Model) {
return data;
}
// Disabled model auto create
if (this.modelClass === false) {
return data;
}
// Required
if (this.modelClass === null) {
InvalidConfigException('Property `modelClass` in collection is required (or set false to force disable).');
}
// Empty model
if (!data) {
data = {};
}
if (_isObject(data)) {
var modelClass = this.modelClass;
modelClass = Jii.namespace(modelClass);
if (!_isFunction(modelClass)) {
throw new InvalidConfigException('Not found model class for create instance in collection, modelClass: ' + this.modelClass);
}
if (_isFunction(modelClass.instantiate) && _isFunction(modelClass.populateRecord)) {
var model = modelClass.instantiate(data);
modelClass.populateRecord(model, data);
return model;
}
return new modelClass(data);
}
throw new InvalidParamException('Cannot create model instance from data: ' + JSON.stringify(data));
},
_onSort() {
// @todo Trigger sort event
},
/**
* @param {string|string[]} name
* @param {function|object} handler
* @param {*} [data]
* @param {boolean} [isAppend]
*/
on(name, handler, data, isAppend) {
// Multiple names support
name = this._normalizeEventNames(name);
if (name.length > 1) {
_each(name, n => {
this.on(n, handler, data, isAppend)
});
return;
} else {
name = name[0];
}
// Attributes in models
var changeNameFormat = this._detectKeyFormatChangeName(name);
if (changeNameFormat) {
var Model = require('./Model');
var changeNameEvent = Model.EVENT_CHANGE_NAME + changeNameFormat.subName;
this._eventsChangeName.push([changeNameEvent, handler, data, isAppend]);
this.each(model => {
model.on(changeNameEvent, handler, data, isAppend);
});
return;
}
this.__super(name, handler, data, isAppend);
},
/**
* @param {string|string[]} name
* @param {function} [handler]
* @return boolean
*/
off(name, handler) {
// Multiple names support
name = this._normalizeEventNames(name);
if (name.length > 1) {
var bool = false;
_each(name, n => {
if (this.on(n, handler)) {
bool = true;
}
});
return bool;
} else {
name = name[0];
}
// Attributes in models
var changeNameFormat = this._detectKeyFormatChangeName(name);
if (changeNameFormat) {
var Model = require('./Model');
var changeNameEvent = Model.EVENT_CHANGE_NAME + changeNameFormat.subName;
this._eventsChangeName = _filter(this._eventsChangeName, arr => {
return arr[0] !== changeNameEvent || arr[1] !== handler;
});
var bool = false;
this.each(model => {
if (model.off(changeNameEvent, handler)) {
bool = true;
}
});
return bool;
}
return this.__super(name, handler);
},
_detectKeyFormatChangeName(name) {
if (name.indexOf(this.__static.EVENT_CHANGE_NAME) !== 0) {
return null;
}
return {
subName: name.substr(this.__static.EVENT_CHANGE_NAME.length)
};
},
// Array prototype
/////////////////////
/**
*
* @param {...*} value1
* @returns {self}
*/
concat(value1) {
this.add(_toArray(arguments));
return this;
},
/**
*
*/
reverse() {
Array.prototype.reverse.call(this);
this._onSort();
},
/**
*
*/
sort() {
Array.prototype.sort.call(this);
this._onSort();
},
/**
*
*/
toArray() {
return this;
},
/**
*
*/
join() {
// @todo
throw new NotSupportedException();
},
/**
*
*/
toString() {
// @todo
throw new NotSupportedException();
},
/**
*
*/
toLocaleString() {
// @todo
throw new NotSupportedException();
},
/**
*
*
* @param {number} start
* @param {number} deleteCount
* @param {...object} [model1]
* @returns {[]}
*/
splice(start, deleteCount, model1) {
var toRemove = Array.prototype.slice.call(this, start, start + deleteCount);
this.remove(toRemove);
this.add(_toArray(arguments).slice(2), start);
return toRemove;
},
/**
*
* @param begin
* @param end
* @returns {*}
*/
slice(begin, end) {
return new this.__static(Array.prototype.slice.call(this, begin, end), {
modelClass: this.modelClass
});
},
/**
*
* @param {...object} model
*/
push(model) {
this.add(_toArray(arguments));
},
/**
*
* @returns {object}
*/
pop() {
if (this.length === 0) {
return null;
}
var model = this[this.length - 1];
this.remove(model);
return model;
},
/**
*
* @param {...object} model1
* @returns {number}
*/
unshift(model1) {
this.add(_toArray(arguments), 0);
return this.length;
},
/**
*
* @returns {object}
*/
shift() {
if (this.length === 0) {
return null;
}
var model = this[0];
this.remove(model);
return model;
},
// @todo ES6 methods
//es6 copyWithin: function() {},
//es6 entries: function() {},
//es6 fill: function() {},
//es6 keys: function() {},
//es6 values: function() {},
// Underscore methods
/////////////////////
/**
*
* @param {function} iteratee
*/
each(iteratee) {
return _each(this, iteratee);
},
/**
*
* @param {function} iteratee
*/
forEach(iteratee) {
return this.each.apply(this, arguments);
},
/**
*
* @param {function} iteratee
* @returns {[]}
*/
map(iteratee) {
return _map(this, iteratee);
},
/**
*
* @param {function} iteratee
* @param {*} [memo]
* @returns {[]}
*/
reduce(iteratee, memo) {
return _reduce(this, iteratee, memo);
},
/**
*
* @param {function} iteratee
* @param {*} [memo]
* @returns {[]}
*/
reduceRight(iteratee, memo) {
return _reduceRight(this, iteratee, memo);
},
/**
*
* @param {function} predicate
* @returns {object|Jii.base.Model|null}
*/
find(predicate) {
return _find(this, this._normalizePredicate(predicate)) || null;
},
/**
*
* @param {function} predicate
* @returns {[]}
*/
filter(predicate) {
return _filter(this, this._normalizePredicate(predicate));
},
/**
*
* @param {object} properties
* @returns {[]}
*/
where(properties) {
return _filter(this, properties);
},
/**
*
* @param {object} properties
* @returns {object|Jii.base.Model|null}
*/
findWhere(properties) {
return _find(this, properties) || null;
},
/**
*
* @param {function} predicate
* @returns {[]}
*/
reject(predicate) {
return _reject(this, this._normalizePredicate(predicate));
},
/**
*
* @param {function} [predicate]
*/
every(predicate) {
return _every(this, this._normalizePredicate(predicate));
},
/**
*
* @param {function} [predicate]
*/
some(predicate) {
return _some(this, this._normalizePredicate(predicate));
},
/**
*
* @param {string} propertyName
* @returns {Array}
*/
pluck(propertyName) {
return _map(this, model => _isFunction(model.get) ? model.get(propertyName) : model[propertyName]);
},
/**
*
* @param {function} [iteratee]
* @returns {object}
*/
max(iteratee) {
return _maxBy(this, iteratee);
},
/**
*
* @param {function} [iteratee]
* @returns {object}
*/
min(iteratee) {
return _minBy(this, iteratee);
},
/**
*
* @param {string|function} value
* @returns {[]}
*/
sortBy(value) {
var iterator = _isFunction(value) ?
value :
model => _isFunction(model.get) ? model.get(value) : model[value];
_each(_sortBy(this, iterator), (model, i) => {
this[i] = model;
});
this._onSort();
},
/**
*
* @param {string|function} value
* @returns {[]}
*/
groupBy(value) {
var iterator = _isFunction(value) ?
value :
model => _isFunction(model.get) ? model.get(value) : model[value];
return _groupBy(this, iterator);
},
/**
*
* @param {string|function} value
* @returns {[]}
*/
/*indexBy(value) {
var iterator = _isFunction(value) ?
value :
model => _isFunction(model.get) ? model.get(value) : model[value];
return _indexBy(this, iterator);
},*/
/**
*
* @param {string|function} value
* @returns {[]}
*/
countBy(value) {
var iterator = _isFunction(value) ?
value :
model => _isFunction(model.get) ? model.get(value) : model[value];
return _countBy(this, iterator);
},
/**
*
* @returns {number}
*/
size() {
return this.length;
},
/**
*
* @param [num]
* @returns {number}
*/
first(num) {
return _first(this, num);
},
/**
*
* @param [num]
* @returns {[]}
*/
initial(num) {
return _initial(this, num);
},
/**
*
* @param [num]
* @returns {number}
*/
last(num) {
return _last(this, num);
},
/**
*
* @param [index]
* @returns {number}
*/
rest(index) {
return _drop(this, index);
},
/**
*
* @param {...*} [value]
* @returns {[]}
*/
without(value) {
var args = _toArray(arguments);
args.unshift(this);
return _without.apply(null, args);
},
/**
*
* @param {*} [value]
* @param {boolean} [isSorted]
* @returns {number}
*/
indexOf(value, isSorted) {
return _indexOf(this, value, isSorted);
},
/**
*
* @param {*} value
* @param {number} [fromIndex]
* @returns {object}
*/
lastIndexOf(value, fromIndex) {
return _lastIndexOf(this, value, fromIndex);
},
/**
*
* @param {object} model
* @param {*} value
* @returns {number}
*/
/*sortedIndex(model, value) {
var iterator = _isFunction(value) ?
value :
model => _isFunction(model.get) ? model.get(value) : model[value];
return _sortedIndex(this, model, iterator);
},*/
/**
*
* @param {function} predicate
* @returns {number}
*/
findIndex(predicate) {
return _findIndex(this, this._normalizePredicate(predicate));
},
/**
*
* @param {function} predicate
* @returns {number}
*/
findLastIndex(predicate) {
return _findLastIndex(this, this._normalizePredicate(predicate));
},
/**
*
*/
shuffle() {
_shuffle(this);
},
/**
*
* @returns {boolean}
*/
isEmpty() {
return this.length === 0;
},
_normalizePredicate(predicate) {
// TODO Instance of without require deps
if (_isObject(predicate) && _isFunction(predicate.createCommand) && _isFunction(predicate.prepare) && this.modelClass) {
var db = Jii.namespace(this.modelClass).getDb();
if (db) {
var filterBuilder = db.getSchema().getFilterBuilder();
var query = predicate;
filterBuilder.prepare(query);
predicate = filterBuilder.createFilter(query);
predicate.query = query;
predicate.attributes = filterBuilder.attributes(query);
} else {
throw new InvalidConfigException('Not found db component in model.');
}
}
return predicate;
}
});
module.exports = Collection;