UNPKG

sutando

Version:

A modern Node.js ORM. Makes it enjoyable to interact with your database. Support Mysql, MSSql, MariaDB, Sqlite.

268 lines (207 loc) 6.15 kB
const { collect, Collection: BaseCollection } = require('collect.js'); const difference = require('lodash/difference'); const pick = require('lodash/pick'); const omit = require('lodash/omit'); const isEmpty = require('lodash/isEmpty'); const isArray = require('lodash/isArray'); class Collection extends BaseCollection { async load(...relations) { if (this.isNotEmpty()) { const query = this.first().constructor.query().with(...relations); const items = await query.eagerLoadRelations(this.items); return new this.constructor(items) } return this; } async loadAggregate(relations, column, action = null) { if (this.isEmpty()) { return this; } const models = (await this.first().newModelQuery() .whereIn(this.first().getKeyName(), this.modelKeys()) .select(this.first().getKeyName()) .withAggregate(relations, column, action) .get()) .keyBy(this.first().getKeyName()); const attributes = difference( Object.keys(models.first().getAttributes()), [models.first().getKeyName()] ); this.each((model) => { const extraAttributes = pick(models.get(model.getKey()).getAttributes(), attributes); model.fill(extraAttributes) .syncOriginalAttributes(attributes); }); return this; } loadCount(relations) { return this.loadAggregate(relations, '*', 'count'); } loadMax(relation, column) { return this.loadAggregate(relation, column, 'max'); } loadMin(relation, column) { return this.loadAggregate(relation, column, 'min'); } loadSum(relation, column) { return this.loadAggregate(relation, column, 'sum'); } loadAvg(relation, column) { return this.loadAggregate(relation, column, 'avg'); } mapThen(callback) { return Promise.all(this.map(callback)); } modelKeys() { return this.all().map(item => item.getKey()); } contains(key, operator = null, value = null) { if (arguments.length > 1) { return super.contains(key, operator, value); } const Model = require('./model'); if (key instanceof Model) { return super.contains(model => { return model.is(key); }); } return super.contains(model => { return model.getKey() == key; }); } diff(items) { const diff = new this.constructor; const dictionary = this.getDictionary(items); this.items.map(item => { if (dictionary[item.getKey()] === undefined) { diff.add(item); } }); return diff; } except(keys) { const dictionary = omit(this.getDictionary(), keys); return new this.constructor(Object.values(dictionary)); } intersect(items) { const intersect = new this.constructor; if (isEmpty(items)) { return intersect; } const dictionary = this.getDictionary(items); for (let item of this.items) { if (dictionary[item.getKey()] !== undefined) { intersect.add(item); } } return intersect; } unique(key = null, strict = false) { if (key !== null) { return super.unique(key, strict); } return new this.constructor(Object.values(this.getDictionary())); } find(key, defaultValue = null) { const Model = require('./model'); if (key instanceof Model) { key = key.getKey(); } if (isArray(key)) { if (this.isEmpty()) { return new this.constructor; } return this.whereIn(this.first().getKeyName(), key); } collect(this.items).first(model => { return model.getKey() == key; }) return this.items.filter(model => { return model.getKey() == key; })[0] || defaultValue; } async fresh(...args) { if (this.isEmpty()) { return new this.constructor; } const model = this.first(); const freshModels = (await model.newQuery() .with(...args) .whereIn(model.getKeyName(), this.modelKeys()) .get()) .getDictionary(); return this.filter(model => { return model.exists && freshModels[model.getKey()] !== undefined; }).map(model => { return freshModels[model.getKey()]; }); } makeVisible(attributes) { return this.each(item => { item.makeVisible(attributes); }) } makeHidden(attributes) { return this.each(item => { item.makeHidden(attributes); }) } append(attributes) { return this.each(item => { item.append(attributes); }) } only(keys) { if (keys === null) { return new Collection(this.items); } const dictionary = pick(this.getDictionary(), keys); return new this.constructor(Object.values(dictionary)); } getDictionary(items = null) { items = items === null ? this.items : items; const dictionary = {}; items.map(value => { dictionary[value.getKey()] = value; }); return dictionary; } toQuery() { const model = this.first(); if (! model) { throw new Error('Unable to create query for empty collection.'); } const modelName = model.constructor.name; if (this.filter(model => { return ! (model instanceof modelName); }).isNotEmpty()) { throw new Error('Unable to create query for collection with mixed types.'); } return model.newModelQuery().whereKey(this.modelKeys()); } toData() { return this.all().map(item => typeof item.toData == 'function' ? item.toData() : item); } toJSON() { return this.toData(); } toJson(...args) { return JSON.stringify(this.toData(), ...args); } [Symbol.iterator]() { const items = this.items; let length = this.items.length; let n = 0; return { next() { return n < length ? { value: items[n++], done: false } : { done: true }; } }; } } module.exports = Collection;