UNPKG

@type-r/models

Version:

The serializable type system for JS and TypeScript

397 lines 15.7 kB
import { __assign, __decorate, __extends } from "tslib"; import { Linked } from '@linked/value'; import { define, definitions, EventMap, eventsApi, logger, Mixable, mixinRules, mixins } from '@type-r/mixture'; import { startIO } from '../io-tools'; import { AggregatedType, Model, SharedType, shared, attributes } from '../model'; import { ItemsBehavior, Transactional, transactionApi } from '../transactions'; import { addTransaction } from './add'; import { ArrayMixin } from './arrayMethods'; import { free, sortElements, updateIndex } from './commons'; import { removeMany, removeOne } from './remove'; import { emptySetTransaction, setTransaction } from './set'; var trigger2 = eventsApi.trigger2, begin = transactionApi.begin, commit = transactionApi.commit, markAsDirty = transactionApi.markAsDirty; var _count = 0; var CollectionRefsType = (function (_super) { __extends(CollectionRefsType, _super); function CollectionRefsType() { return _super !== null && _super.apply(this, arguments) || this; } CollectionRefsType.defaultValue = []; return CollectionRefsType; }(SharedType)); ; var Collection = (function (_super) { __extends(Collection, _super); function Collection(records, options, shared) { if (options === void 0) { options = {}; } var _this = _super.call(this, _count++) || this; _this.models = []; _this._byId = {}; _this.comparator = _this.comparator; if (options.comparator !== void 0) { _this.comparator = options.comparator; options.comparator = void 0; } _this.model = _this.model; if (options.model) { _this.model = options.model; options.model = void 0; } _this.idAttribute = _this.model.prototype.idAttribute; _this._shared = shared || 0; if (records) { var elements = toElements(_this, records, options); emptySetTransaction(_this, elements, options, true); } _this.initialize.apply(_this, arguments); if (_this._localEvents) _this._localEvents.subscribe(_this, _this); return _this; } Collection_1 = Collection; Collection.of = function (Ctor) { return typeof Ctor === 'function' ? Ctor.Collection : attributes(Ctor).Collection; }; Collection.ofRefs = function (Ctor) { return Ctor.Collection.Refs; }; Collection.prototype.createSubset = function (models, options) { throw new ReferenceError('Failed dependency injection'); }; Collection.onExtend = function (BaseClass) { var Ctor = this; this._SubsetOf = null; function RefsCollection(a, b, listen) { Ctor.call(this, a, b, ItemsBehavior.share | (listen ? ItemsBehavior.listen : 0)); } Mixable.mixins.populate(RefsCollection); RefsCollection.create = Collection_1.create; RefsCollection.prototype = this.prototype; RefsCollection._metatype = CollectionRefsType; this.Refs = this.Subset = RefsCollection; Transactional.onExtend.call(this, BaseClass); }; Collection.onDefine = function (definition, BaseClass) { if (definition.itemEvents) { var eventsMap = new EventMap(BaseClass.prototype._itemEvents); eventsMap.addEventsMap(definition.itemEvents); this.prototype._itemEvents = eventsMap; } if (definition.comparator !== void 0) this.prototype.comparator = definition.comparator; Transactional.onDefine.call(this, definition); }; Object.defineProperty(Collection.prototype, "__inner_state__", { get: function () { return this.models; }, enumerable: true, configurable: true }); Object.defineProperty(Collection.prototype, "comparator", { get: function () { return this._comparator; }, set: function (x) { var _this = this; switch (typeof x) { case 'string': this._comparator = function (a, b) { var aa = a[x], bb = b[x]; if (aa === bb) return 0; return aa < bb ? -1 : +1; }; break; case 'function': if (x.length === 1) { this._comparator = function (a, b) { var aa = x.call(_this, a), bb = x.call(_this, b); if (aa === bb) return 0; return aa < bb ? -1 : +1; }; } else { this._comparator = function (a, b) { return x.call(_this, a, b); }; } break; default: this._comparator = null; } }, enumerable: true, configurable: true }); Collection.prototype.getStore = function () { return this._store || (this._store = this._owner ? this._owner.getStore() : this._defaultStore); }; Collection.prototype._onChildrenChange = function (record, options, initiator) { if (options === void 0) { options = {}; } if (initiator === this) return; var idAttribute = this.idAttribute; if (record.hasChanged(idAttribute)) { updateIndex(this._byId, record); } var isRoot = begin(this); if (markAsDirty(this, options)) { trigger2(this, 'change', record, options); } isRoot && commit(this); }; Collection.prototype.get = function (objOrId) { if (objOrId == null) return; if (typeof objOrId === 'object') { var id = objOrId[this.idAttribute]; return (id !== void 0 && this._byId[id]) || this._byId[objOrId.cid]; } else { return this._byId[objOrId]; } }; Collection.prototype[Symbol.iterator] = function () { return this.models[Symbol.iterator](); }; Collection.prototype.updateEach = function (iteratee) { var isRoot = transactionApi.begin(this); this.each(iteratee); isRoot && transactionApi.commit(this); }; Collection.prototype._validateNested = function (errors) { if (this._shared) return 0; var count = 0; this.each(function (record) { var error = record.validationError; if (error) { errors[record.cid] = error; count++; } }); return count; }; Collection.prototype.initialize = function () { }; Collection.prototype.clone = function (options) { if (options === void 0) { options = {}; } var models = this._shared & ItemsBehavior.share ? this.models : this.map(function (model) { return model.clone(); }), copy = new this.constructor(models, { model: this.model, comparator: this.comparator }, this._shared); if (options.pinStore) copy._defaultStore = this.getStore(); return copy; }; Collection.prototype.toJSON = function (options) { return this.map(function (model) { return model.toJSON(options); }); }; Collection.prototype.set = function (elements, options) { if (elements === void 0) { elements = []; } if (options === void 0) { options = {}; } if (options.add !== void 0) { this._log('warn', "Type-R:InvalidOption", "Collection.set doesn't support 'add' option, behaving as if options.add === true.", options); } if (options.reset) { this.reset(elements, options); } else { var transaction = this._createTransaction(elements, options); transaction && transaction.commit(); } return this; }; Collection.prototype.liveUpdates = function (enabled) { var _this = this; if (enabled) { this.liveUpdates(false); var filter_1 = typeof enabled === 'function' ? enabled : function () { return true; }; this._liveUpdates = { updated: function (json) { filter_1(json) && _this.add(json, { parse: true, merge: true }); }, removed: function (id) { return _this.remove(id); } }; return this.getEndpoint().subscribe(this._liveUpdates, this).then(function () { return _this; }); } else { if (this._liveUpdates) { this.getEndpoint().unsubscribe(this._liveUpdates, this); this._liveUpdates = null; } } }; Collection.prototype.fetch = function (a_options) { var _this = this; if (a_options === void 0) { a_options = {}; } var options = __assign({ parse: true }, a_options), endpoint = this.getEndpoint(); return startIO(this, endpoint.list(options, this), options, function (json) { var result = _this.set(json, __assign({ parse: true, ioMethod: 'fetch' }, options)); if (options.liveUpdates) { result = _this.liveUpdates(options.liveUpdates); } return result; }); }; Collection.prototype.dispose = function () { if (this._disposed) return; var aggregated = !this._shared; for (var _i = 0, _a = this.models; _i < _a.length; _i++) { var record = _a[_i]; free(this, record); if (aggregated) record.dispose(); } this.liveUpdates(false); _super.prototype.dispose.call(this); }; Collection.prototype.reset = function (a_elements, options) { if (options === void 0) { options = {}; } var isRoot = begin(this), previousModels = this.models; if (a_elements) { emptySetTransaction(this, toElements(this, a_elements, options), options, true); } else { this._byId = {}; this.models = []; } markAsDirty(this, options); options.silent || trigger2(this, 'reset', this, __assign({ previousModels: previousModels }, options)); var _byId = this._byId; for (var _i = 0, previousModels_1 = previousModels; _i < previousModels_1.length; _i++) { var toDispose = previousModels_1[_i]; _byId[toDispose.cid] || free(this, toDispose); } isRoot && commit(this); return this.models; }; Collection.prototype.add = function (a_elements, options) { if (options === void 0) { options = {}; } var elements = toElements(this, a_elements, options), transaction = this.models.length ? addTransaction(this, elements, options) : emptySetTransaction(this, elements, options); if (transaction) { transaction.commit(); return transaction.added; } }; Collection.prototype.remove = function (recordsOrIds, options) { if (options === void 0) { options = {}; } if (recordsOrIds) { return Array.isArray(recordsOrIds) ? removeMany(this, recordsOrIds, options) : removeOne(this, recordsOrIds, options); } return []; }; Collection.prototype.$includes = function (idOrObj) { return new LinkedIncludes(this, idOrObj); }; Collection.prototype._createTransaction = function (a_elements, options) { if (options === void 0) { options = {}; } var elements = toElements(this, a_elements, options); if (this.models.length) { return options.remove === false ? addTransaction(this, elements, options, true) : setTransaction(this, elements, options); } else { return emptySetTransaction(this, elements, options); } }; Collection.prototype.sort = function (options) { if (options === void 0) { options = {}; } if (sortElements(this, options)) { var isRoot = begin(this); if (markAsDirty(this, options)) { trigger2(this, 'sort', this, options); } isRoot && commit(this); } return this; }; Collection.prototype.unset = function (modelOrId, options) { var value = this.get(modelOrId); this.remove(modelOrId, __assign({ unset: true }, options)); return value; }; Collection.prototype.modelId = function (attrs) { return attrs[this.model.prototype.idAttribute]; }; Collection.prototype.toggle = function (model, a_next) { var prev = Boolean(this.get(model)), next = a_next === void 0 ? !prev : Boolean(a_next); if (prev !== next) { if (prev) { this.remove(model); } else { this.add(model); } } return next; }; Collection.prototype._log = function (level, topic, text, value, a_logger) { (a_logger || logger).trigger(level, topic, this.model.prototype.getClassName() + "." + this.getClassName() + ": " + text, { Argument: value, 'Attributes spec': this.model.prototype._attributes }); }; Collection.prototype.getClassName = function () { return _super.prototype.getClassName.call(this) || 'Collection'; }; Object.defineProperty(Collection.prototype, "length", { get: function () { return this.models.length; }, enumerable: true, configurable: true }); Collection.prototype.push = function (model, options) { return this.add(model, __assign({ at: this.length }, options)); }; Collection.prototype.pop = function (options) { var model = this.at(this.length - 1); this.remove(model, __assign({ unset: true }, options)); return model; }; Collection.prototype.unshift = function (model, options) { return this.add(model, __assign({ at: 0 }, options)); }; Collection.prototype.shift = function (options) { var model = this.at(0); this.remove(model, __assign({ unset: true }, options)); return model; }; var Collection_1; Collection.refsTo = shared; Collection._metatype = AggregatedType; Collection = Collection_1 = __decorate([ define({ cidPrefix: 'c', model: Model, _changeEventName: 'changes', _aggregationError: null }), mixins(ArrayMixin), definitions({ comparator: mixinRules.value, model: mixinRules.protoValue, itemEvents: mixinRules.merge }) ], Collection); return Collection; }(Transactional)); export { Collection }; function toElements(collection, elements, options) { var parsed = options.parse ? collection.parse(elements, options) : elements; return Array.isArray(parsed) ? parsed : [parsed]; } Model.Collection = Collection; var LinkedIncludes = (function (_super) { __extends(LinkedIncludes, _super); function LinkedIncludes(collection, model) { var _this = _super.call(this, collection.get(model)) || this; _this.collection = collection; _this.model = model; return _this; } LinkedIncludes.prototype.set = function (x) { this.collection.toggle(this.model); }; return LinkedIncludes; }(Linked)); //# sourceMappingURL=index.js.map