UNPKG

model-layer

Version:
509 lines 16.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Collection = void 0; const events_1 = require("events"); const Model_1 = require("./Model"); const EqualStack_1 = __importDefault(require("./EqualStack")); const utils_1 = require("./utils"); const errors_1 = require("./errors"); class Collection extends events_1.EventEmitter { constructor(rows) { super(); if (!this.constructor.prototype.hasOwnProperty("ModelConstructor")) { this.constructor.prototype.ModelConstructor = this.Model(); // prepare model structure without calling constructor const model = Object.create(this.ModelConstructor.prototype); model.prepareStructure(); } this.models = []; if (rows instanceof Array) { rows.forEach((row) => { const model = this.prepareRow(row); this.models.push(model); }); this.length = rows.length; } else { this.length = 0; } } at(index, rowOrModel) { // set if (rowOrModel) { const removedModel = this.models[index]; const model = this.prepareRow(rowOrModel); this.models[index] = model; this.length = this.models.length; if (removedModel) { const removeEvent = { type: "remove", collection: this, model: removedModel }; this.emit("remove", removeEvent); } const addEvent = { type: "add", model, collection: this }; this.emit("add", addEvent); } // get else { return this.models[index]; } } prepareRow(row) { let model; if (row instanceof this.ModelConstructor) { model = row; return model; } if (row instanceof Model_1.Model) { throw new errors_1.WrongModelConstructorError({ invalid: row.constructor.name, expected: this.ModelConstructor.name, collection: this.constructor.name }); } if (utils_1.isPlainObject(row)) { model = new this.ModelConstructor(row); } else { throw new errors_1.InvalidModelRowError({ model: this.ModelConstructor.name, invalidValue: utils_1.invalidValuesAsString(row) }); } return model; } push(...models) { if (!models.length) { return; } const addedModels = []; for (let i = 0, n = models.length; i < n; i++) { const inputModel = models[i]; const model = this.prepareRow(inputModel); addedModels.push(model); this.models.push(model); } this.length = this.models.length; for (let i = 0, n = addedModels.length; i < n; i++) { const model = addedModels[i]; const addEvent = { type: "add", model, collection: this }; this.emit("add", addEvent); } } add(...models) { if (!models.length) { return; } let inputModels = []; for (let i = 0, n = models.length; i < n; i++) { const modelOrArr = models[i]; if (Array.isArray(modelOrArr)) { const arr = modelOrArr; inputModels = inputModels.concat(arr); } else { const model = modelOrArr; inputModels.push(model); } } const addedModels = []; for (let i = 0, n = inputModels.length; i < n; i++) { let model = inputModels[i]; model = this.prepareRow(model); addedModels.push(model); this.models.push(model); } this.length = this.models.length; for (let i = 0, n = addedModels.length; i < n; i++) { const model = addedModels[i]; const addEvent = { type: "add", model, collection: this }; this.emit("add", addEvent); } } forEach(iteration, context) { this.models.forEach(iteration, context || this); } each(iteration, context) { this.models.forEach(iteration, context || this); } find(iteration, context) { return this.models.find(iteration, context || this); } findIndex(iteration, context) { return this.models.findIndex(iteration, context || this); } filter(iteration, context) { return this.models.filter(iteration, context || this); } map(iteration, context) { return this.models.map(iteration, context || this); } flatMap(iteration, context) { const result = this.models.map(iteration, context || this); let output = []; for (let i = 0, n = result.length; i < n; i++) { const elem = result[i]; if (Array.isArray(elem)) { output = output.concat(elem); } else { output.push(elem); } } return output; } reduce(iteration, initialValue) { const reduced = this.models.reduce(iteration, initialValue); return reduced; } reduceRight(iteration, initialValue) { const reduced = this.models.reduceRight(iteration, initialValue); return reduced; } every(iteration, context) { return this.models.every(iteration, context || this); } some(iteration, context) { return this.models.some(iteration, context || this); } slice(begin, end) { return this.models.slice(begin, end); } flat() { return this.models.slice(); } indexOf(searchElement, fromIndex) { return this.models.indexOf(searchElement, fromIndex); } lastIndexOf(searchElement, fromIndex) { if (arguments.length === 2) { return this.models.lastIndexOf(searchElement, fromIndex); } else { return this.models.lastIndexOf(searchElement); } } includes(searchElement, fromIndex) { return this.models.includes(searchElement, fromIndex); } pop() { const model = this.models.pop(); this.length = this.models.length; if (model) { const removeEvent = { type: "remove", collection: this, model }; this.emit("remove", removeEvent); } return model; } shift() { const model = this.models.shift(); this.length = this.models.length; if (model) { const removeEvent = { type: "remove", collection: this, model }; this.emit("remove", removeEvent); } return model; } unshift(...models) { if (!models.length) { return; } const preparedModels = []; for (let i = 0, n = models.length; i < n; i++) { const row = models[i]; const model = this.prepareRow(row); preparedModels.push(model); } this.models.unshift.apply(this.models, preparedModels); this.length = this.models.length; for (let i = 0, n = preparedModels.length; i < n; i++) { const model = preparedModels[i]; const addEvent = { type: "add", model, collection: this }; this.emit("add", addEvent); } } sort(compareFunctionOrKey, ...otherKeys) { if (typeof compareFunctionOrKey === "string") { const firstKey = compareFunctionOrKey; // order by key asc if (!otherKeys.length) { const key = firstKey; this.models.sort((modelA, modelB) => { const valueA = modelA.get(key); const valueB = modelB.get(key); return valueA > valueB ? 1 : -1; }); } // order by key1 asc, key2 asc, ... else { const keys = [firstKey].concat(otherKeys); this.models.sort((modelA, modelB) => { for (let i = 0, n = keys.length; i < n; i++) { const key = keys[i]; const valueA = modelA.get(key); const valueB = modelB.get(key); if (valueA > valueB) { return 1; } if (valueA < valueB) { return -1; } } return 0; }); } } // sort by compareFunction( (modelA, modelB) => ... ) else if (typeof compareFunctionOrKey === "function") { const compareFunction = compareFunctionOrKey; this.models.sort(compareFunction); } else { const invalidValue = utils_1.invalidValuesAsString(compareFunctionOrKey); throw new errors_1.InvalidSortParamsError({ invalidValue }); } } reverse() { this.models.reverse(); return this; } concat(...values) { const CustomCollection = this.constructor; let outputModels = this.models; for (let i = 0, n = values.length; i < n; i++) { const rowsOrCollection = values[i]; if (rowsOrCollection instanceof Collection) { const collection = rowsOrCollection; outputModels = outputModels.concat(collection.models); } else { const rows = rowsOrCollection; const models = rows.map((row) => this.prepareRow(row)); outputModels = outputModels.concat(models); } } return new CustomCollection(outputModels); } join(separator = ",") { return this.models.join(separator); } // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/fill fill(row, start, end) { // Step 3-5. // tslint:disable-next-line: no-bitwise const len = this.length >>> 0; // Step 6-7. start = arguments[1]; // tslint:disable-next-line: no-bitwise const relativeStart = start >> 0; // Step 8. let k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len); // Step 9-10. end = arguments[2]; const relativeEnd = end === undefined ? // tslint:disable-next-line: no-bitwise len : end >> 0; // Step 11. const final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len); // Step 12. const addedModels = []; while (k < final) { const model = this.prepareRow(row); addedModels.push(model); this.models[k] = model; k++; } for (let i = 0, n = addedModels.length; i < n; i++) { const model = addedModels[i]; const addEvent = { type: "add", model, collection: this }; this.emit("add", addEvent); } // Step 13. return this; } splice(start, deleteCount, ...inputItems) { let items; if (inputItems && inputItems.length) { items = inputItems.map((row) => this.prepareRow(row)); } else { items = []; } const removedModels = this.models.slice(start, start + deleteCount); this.models.splice(start, deleteCount, ...items); this.length = this.models.length; for (let i = 0, n = removedModels.length; i < n; i++) { const model = removedModels[i]; const removeEvent = { type: "remove", collection: this, model }; this.emit("remove", removeEvent); } for (let i = 0, n = items.length; i < n; i++) { const model = items[i]; const addEvent = { type: "add", model, collection: this }; this.emit("add", addEvent); } } reset() { const removedModels = this.models.slice(); this.models = []; this.length = 0; for (let i = 0, n = removedModels.length; i < n; i++) { const model = removedModels[i]; const removeEvent = { type: "remove", collection: this, model }; this.emit("remove", removeEvent); } } first() { return this.models[0]; } last() { return this.models[this.models.length - 1]; } create(row) { const model = this.prepareRow(row); this.models.push(model); this.length = this.models.length; const addEvent = { type: "add", model, collection: this }; this.emit("add", addEvent); return model; } toJSON(stack = []) { return this.models.map((model) => model.toJSON(stack)); } clone(stack) { stack = stack || new EqualStack_1.default(); const existsClone = stack.get(this); if (existsClone) { return existsClone; } const clone = Object.create(this.constructor.prototype); stack.add(this, clone); const models = this.models.map((model) => model.clone(stack)); clone.models = models; clone.length = models.length; return clone; } remove(idOrModel) { let index = -1; let removedModel; if (idOrModel instanceof Model_1.Model) { const model = idOrModel; index = this.models.indexOf(model); removedModel = model; } else { const id = idOrModel; index = this.models.findIndex((model) => model.primaryValue === id); removedModel = this.models[index]; } if (index !== -1) { this.models.splice(index, 1); this.length = this.models.length; } if (removedModel) { const removeEvent = { type: "remove", collection: this, model: removedModel }; this.emit("remove", removeEvent); } } get(id) { return this.find((model) => model.primaryValue === id); } equal(otherCollection, stack) { if (!(otherCollection instanceof Collection) && !Array.isArray(otherCollection)) { return false; } if (this.length !== otherCollection.length) { return false; } stack = stack || new EqualStack_1.default(); // stop circular recursion const stacked = stack.get(this); if (stacked) { return stacked === otherCollection; } stack.add(this, otherCollection); for (let i = 0, n = this.length; i < n; i++) { const selfModel = this.at(i); const otherModel = otherCollection instanceof Collection ? otherCollection.at(i) : otherCollection[i]; const isEqual = selfModel.equal(otherModel, stack); if (!isEqual) { return false; } } return true; } on(eventName, handler) { super.on(eventName, handler); } } exports.Collection = Collection; // for js Collection.prototype.Model = function () { throw new errors_1.CollectionShouldHaveModelError({ className: this.constructor.name }); }; exports.default = Collection; //# sourceMappingURL=Collection.js.map