1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 | 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray'); var _slicedToArray3 = _interopRequireDefault(_slicedToArray2); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _helpers = require('./helpers'); var _helpers2 = _interopRequireDefault(_helpers); var _promise = require('./base/promise'); var _promise2 = _interopRequireDefault(_promise); var _eager = require('./base/eager'); var _eager2 = _interopRequireDefault(_eager); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // EagerRelation // --------------- var getAttributeUnique = function getAttributeUnique(models, attribute) { return _lodash2.default.uniq(_lodash2.default.map(models, function (m) { return m.get(attribute); })); }; // An `EagerRelation` object temporarily stores the models from an eager load, // and handles matching eager loaded objects with their parent(s). The // `tempModel` is only used to retrieve the value of the relation method, to // know the constraints for the eager query. var EagerRelation = function (_EagerBase) { (0, _inherits3.default)(EagerRelation, _EagerBase); function EagerRelation() { (0, _classCallCheck3.default)(this, EagerRelation); return (0, _possibleConstructorReturn3.default)(this, (EagerRelation.__proto__ || Object.getPrototypeOf(EagerRelation)).apply(this, arguments)); } (0, _createClass3.default)(EagerRelation, [{ key: 'eagerFetch', // Handles an eager loaded fetch, passing the name of the item we're fetching // for, and any options needed for the current fetch. value: function eagerFetch(relationName, handled, options) { var _this2 = this; var relatedData = handled.relatedData; // skip eager loading for rows where the foreign key isn't set if (relatedData.parentFk === null) return; if (relatedData.type === 'morphTo') { return this.morphToFetch(relationName, relatedData, options); } return handled.sync((0, _extends3.default)({}, options, { parentResponse: this.parentResponse })).select().tap(function (response) { return _this2._eagerLoadHelper(response, relationName, handled, _lodash2.default.omit(options, 'parentResponse')); }); } // Special handler for the eager loaded morph-to relations, this handles the // fact that there are several potential models that we need to be fetching // against. pairing them up onto a single response for the eager loading. }, { key: 'morphToFetch', value: function morphToFetch(relationName, relatedData, options) { var _this3 = this; var columnNames = relatedData.columnNames || []; var morphName = relatedData.morphName; var _columnNames = (0, _slicedToArray3.default)(columnNames, 2), _columnNames$ = _columnNames[0], typeColumn = _columnNames$ === undefined ? morphName + '_type' : _columnNames$, _columnNames$2 = _columnNames[1], idColumn = _columnNames$2 === undefined ? morphName + '_id' : _columnNames$2; var parentsByType = _lodash2.default.groupBy(this.parent, function (model) { return model.get(typeColumn); }); var TargetByType = _lodash2.default.mapValues(parentsByType, function (parents, type) { return _helpers2.default.morphCandidate(relatedData.candidates, type); }); return _promise2.default.all(_lodash2.default.map(parentsByType, function (parents, type) { var Target = TargetByType[type]; var idAttribute = _lodash2.default.result(Target.prototype, 'idAttribute'); var ids = getAttributeUnique(parents, idColumn); return Target.query('whereIn', idAttribute, ids).sync(options).select().tap(function (response) { var clone = relatedData.instance('morphTo', Target, { morphName: morphName, columnNames: columnNames }); return _this3._eagerLoadHelper(response, relationName, { relatedData: clone }, options); }); })).then(_lodash2.default.flatten); } // Handles the eager load for both the `morphTo` and regular cases. }, { key: '_eagerLoadHelper', value: function _eagerLoadHelper(response, relationName, handled, options) { var _this4 = this; var relatedModels = this.pushModels(relationName, handled, response); var relatedData = handled.relatedData; return _promise2.default.try(function () { // If there is a response, fetch additional nested eager relations, if any. if (response.length > 0 && options.withRelated) { var relatedModel = relatedData.createModel(); // If this is a `morphTo` relation, we need to do additional processing // to ensure we don't try to load any relations that don't look to exist. if (relatedData.type === 'morphTo') { var withRelated = _this4._filterRelated(relatedModel, options); if (withRelated.length === 0) return; options = _lodash2.default.extend({}, options, { withRelated: withRelated }); } return new EagerRelation(relatedModels, response, relatedModel).fetch(options).return(response); } }).tap(function () { return _promise2.default.map(relatedModels, function (model) { return model.triggerThen('fetched', model, model.attributes, options); }); }); } // Filters the `withRelated` on a `morphTo` relation, to ensure that only valid // relations are attempted for loading. }, { key: '_filterRelated', value: function _filterRelated(relatedModel, options) { // By this point, all withRelated should be turned into a hash, so it should // be fairly simple to process by splitting on the dots. return _lodash2.default.reduce(options.withRelated, function (memo, val) { for (var key in val) { var seg = key.split('.')[0]; if (_lodash2.default.isFunction(relatedModel[seg])) memo.push(val); } return memo; }, []); } }]); return EagerRelation; }(_eager2.default); exports.default = EagerRelation; |