"use strict";

Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.Util = undefined;

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _stackerjsDb = require("stackerjs-db");

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Util = exports.Util = function () {
    function Util() {
        _classCallCheck(this, Util);
    }

    _createClass(Util, null, [{
        key: "makeEntity",
        value: function () {
            var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(defaultEntity, attributes) {
                var withs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
                var metadata, entity, properties, relations;
                return regeneratorRuntime.wrap(function _callee$(_context) {
                    while (1) {
                        switch (_context.prev = _context.next) {
                            case 0:
                                if (Array.isArray(withs)) withs = this.prepareAssociations(withs);

                                metadata = defaultEntity.metadata();
                                entity = Object.create(defaultEntity), properties = {
                                    _attributes: {
                                        value: attributes
                                    }
                                }, relations = {};


                                this.makeEntityFields(properties, attributes, entity, metadata);
                                Object.defineProperties(entity, properties);

                                _context.next = 7;
                                return this.makeEntityRelations(relations, attributes, entity, metadata, withs);

                            case 7:
                                Object.defineProperties(entity, relations);

                                return _context.abrupt("return", entity);

                            case 9:
                            case "end":
                                return _context.stop();
                        }
                    }
                }, _callee, this);
            }));

            function makeEntity(_x2, _x3) {
                return _ref.apply(this, arguments);
            }

            return makeEntity;
        }()
    }, {
        key: "fieldValueParser",
        value: function fieldValueParser(type, value) {
            if (type === "boolean") return value === 1;else if (type === "date") return new Date(value);else if (type === "json") {
                try {
                    return JSON.parse(value);
                } catch (err) {
                    return value;
                }
            } else if (type === "created_at" || type === "updated_at") return value ? value * 1000 : null;else return value;
        }
    }, {
        key: "MANYMANYAssociation",
        value: function MANYMANYAssociation(entity, relation) {
            var _this = this;

            var withs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];

            var expr = _stackerjsDb.DB.Factory.getQueryCriteria();
            var queryBuilder = _stackerjsDb.DB.Factory.getQueryBuilder().select().from(relation.table).set(relation.referencedEntity.metadata().table + ".*").join("INNER", relation.referencedEntity.metadata().table, relation.table + "." + relation.referencedField + " = " + (relation.referencedEntity.metadata().table + ".id")).where(expr.eq(relation.field, entity["_attributes"]["id"]));

            return function () {
                return queryBuilder.execute().then(function (results) {
                    return Promise.all(results.map(function (result) {
                        return _this.makeEntity(relation.referencedEntity, result, withs);
                    }));
                });
            };
        }
    }, {
        key: "HASONEAssociation",
        value: function HASONEAssociation(entity, relation) {
            var _this2 = this;

            var withs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];

            var expr = _stackerjsDb.DB.Factory.getQueryCriteria();
            var queryBuilder = _stackerjsDb.DB.Factory.getQueryBuilder().select().from(relation.referencedEntity.metadata().table).set("*").where(expr.eq(relation.referencedField, entity["_attributes"][relation.field])).limit(1);

            return function () {
                return queryBuilder.execute().then(function (results) {
                    if (results.length <= 0) return Promise.resolve(null);

                    return _this2.makeEntity(relation.referencedEntity, results[0], withs);
                });
            };
        }
    }, {
        key: "HASMANYAssociation",
        value: function HASMANYAssociation(entity, relation) {
            var _this3 = this;

            var withs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];

            var expr = _stackerjsDb.DB.Factory.getQueryCriteria();
            var queryBuilder = _stackerjsDb.DB.Factory.getQueryBuilder().select().from(relation.referencedEntity.metadata().table).set("*").where(expr.eq(relation.referencedField, entity["_attributes"][relation.field]));

            return function () {
                return queryBuilder.execute().then(function (results) {
                    return Promise.all(results.map(function (result) {
                        return _this3.makeEntity(relation.referencedEntity, result, withs);
                    }));
                });
            };
        }
    }, {
        key: "makeEntityFields",
        value: function makeEntityFields(properties, attributes, entity, metadata) {
            var _this4 = this;

            metadata.fields.forEach(function (field) {
                if (typeof attributes[field.name] !== "undefined") {
                    var name = field.alias ? field.alias : field.name;
                    properties[name] = {
                        enumerable: true,
                        writable: true,
                        value: _this4.fieldValueParser(field.type, attributes[field.name])
                    };
                    properties._attributes.value[field.name] = _this4.fieldValueParser(field.type, attributes[field.name]);
                }
            });
        }
    }, {
        key: "makeEntityRelations",
        value: function () {
            var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(properties, attributes, entity, metadata, withs) {
                var _this5 = this;

                return regeneratorRuntime.wrap(function _callee3$(_context3) {
                    while (1) {
                        switch (_context3.prev = _context3.next) {
                            case 0:
                                _context3.next = 2;
                                return Promise.all(metadata.relations.map(function () {
                                    var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(relation) {
                                        var relationGetter;
                                        return regeneratorRuntime.wrap(function _callee2$(_context2) {
                                            while (1) {
                                                switch (_context2.prev = _context2.next) {
                                                    case 0:
                                                        relationGetter = function relationGetter(chainedWiths) {
                                                            if (relation.type === "HASMANY") return _this5.HASMANYAssociation(entity, relation, chainedWiths)();else if (relation.type === "HASONE" || relation.type === "BELONGSTO") return _this5.HASONEAssociation(entity, relation, chainedWiths)();else if (relation.type === "MANYMANY") return _this5.MANYMANYAssociation(entity, relation, chainedWiths)();

                                                            return null;
                                                        };

                                                        properties[relation.name] = {
                                                            enumerable: typeof withs[relation.name] !== "undefined"
                                                        };

                                                        if (!withs[relation.name]) {
                                                            _context2.next = 8;
                                                            break;
                                                        }

                                                        _context2.next = 5;
                                                        return relationGetter(withs[relation.name]);

                                                    case 5:
                                                        properties[relation.name].value = _context2.sent;
                                                        _context2.next = 9;
                                                        break;

                                                    case 8:
                                                        properties[relation.name].get = relationGetter;

                                                    case 9:
                                                    case "end":
                                                        return _context2.stop();
                                                }
                                            }
                                        }, _callee2, _this5);
                                    }));

                                    return function (_x12) {
                                        return _ref3.apply(this, arguments);
                                    };
                                }()));

                            case 2:
                            case "end":
                                return _context3.stop();
                        }
                    }
                }, _callee3, this);
            }));

            function makeEntityRelations(_x7, _x8, _x9, _x10, _x11) {
                return _ref2.apply(this, arguments);
            }

            return makeEntityRelations;
        }()
    }, {
        key: "prepareAssociations",
        value: function prepareAssociations(withs) {
            var _this6 = this;

            var associations = {};
            withs.forEach(function (w) {
                w = w.split(".");
                if (w[1]) associations[w[0]] = _this6.prepareAssociations(w.slice(1));else associations[w[0]] = {};
            });

            return associations;
        }
    }]);

    return Util;
}();