UNPKG

sarala

Version:

Javascript library to communicate with RESTful API built following JSON API specification. inspired by Laravel’s Eloquent.

595 lines (494 loc) 19.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _regenerator = require('babel-runtime/regenerator'); var _regenerator2 = _interopRequireDefault(_regenerator); var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _lodash = require('lodash'); var _moment = require('moment'); var _moment2 = _interopRequireDefault(_moment); var _saralaJsonApiDataFormatter = require('sarala-json-api-data-formatter'); var _QueryBuilder = require('./QueryBuilder'); var _QueryBuilder2 = _interopRequireDefault(_QueryBuilder); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var formatter = new _saralaJsonApiDataFormatter.Formatter(); var Model = function () { function Model() { (0, _classCallCheck3.default)(this, Model); this.queryBuilder = new _QueryBuilder2.default(); this.selfValidate(); this.type = this.resourceName(); this.links = {}; } // override (0, _createClass3.default)(Model, [{ key: 'fields', value: function fields() { return []; } }, { key: 'dates', value: function dates() { return []; } }, { key: 'relationships', value: function relationships() { return {}; } }, { key: 'computed', value: function computed() { return {}; } }, { key: 'resourceName', value: function resourceName() { return null; } }, { key: 'request', value: function () { var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(config) { return _regenerator2.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: case 'end': return _context.stop(); } } }, _callee, this); })); function request(_x) { return _ref.apply(this, arguments); } return request; }() }, { key: 'makeFetchRequest', // fetch requests value: function () { var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(url) { var requestConfig, response; return _regenerator2.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: requestConfig = { method: 'GET', url: url, headers: { 'Accept': 'application/vnd.api+json' } }; this.queryBuilder.reset(); _context2.next = 4; return this.request(requestConfig); case 4: response = _context2.sent; return _context2.abrupt('return', this.respond(response.data)); case 6: case 'end': return _context2.stop(); } } }, _callee2, this); })); function makeFetchRequest(_x2) { return _ref2.apply(this, arguments); } return makeFetchRequest; }() }, { key: 'get', value: function get() { return this.makeFetchRequest('' + this.resourceUrl() + this.queryBuilder.getQuery()); } }, { key: 'find', value: function find(id) { return this.makeFetchRequest('' + this.resourceUrl() + id + this.queryBuilder.getQuery()); } }, { key: 'all', value: function all() { return this.get(); } }, { key: 'paginate', value: function paginate() { var perPage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10; var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; this.queryBuilder.paginate(perPage, page); return this.makeFetchRequest('' + this.resourceUrl() + this.queryBuilder.getQuery()); } }, { key: 'fetchRelation', value: function () { var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(relationship) { var links = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return _regenerator2.default.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: if ((0, _lodash.isUndefined)(links.self)) { links.self = this.getRelationshipUrl(relationship); } _context3.next = 3; return this.relationships()[relationship].makeFetchRequest(links.self); case 3: this[relationship] = _context3.sent; return _context3.abrupt('return', this[relationship]); case 5: case 'end': return _context3.stop(); } } }, _callee3, this); })); function fetchRelation(_x5) { return _ref3.apply(this, arguments); } return fetchRelation; }() // persist requests }, { key: 'makePersistRequest', value: function () { var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(config) { var response; return _regenerator2.default.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: config.headers = { 'Content-Type': 'application/vnd.api+json', 'Accept': 'application/vnd.api+json' }; _context4.next = 3; return this.request(config); case 3: response = _context4.sent; return _context4.abrupt('return', this.respond(response.data)); case 5: case 'end': return _context4.stop(); } } }, _callee4, this); })); function makePersistRequest(_x7) { return _ref4.apply(this, arguments); } return makePersistRequest; }() }, { key: 'save', value: function save() { if (this.hasOwnProperty('id')) { return this.update(); } return this.create(); } }, { key: 'create', value: function create() { return this.makePersistRequest({ url: this.resourceUrl(), method: 'POST', data: this.serialize(this.data()) }); } }, { key: 'update', value: function update() { return this.makePersistRequest({ url: this.getSelfUrl(), method: 'PUT', data: this.serialize(this.data()) }); } }, { key: 'delete', value: function _delete() { return this.makePersistRequest({ url: this.getSelfUrl(), method: 'DELETE' }); } }, { key: 'attach', value: function attach(model) { var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var config = { url: this.getSelfUrl() + '/' + model.type + '/' + model.id, method: 'POST' }; if (data) { config.data = data; } return this.makePersistRequest(config); } }, { key: 'detach', value: function detach(model) { return this.makePersistRequest({ url: this.getSelfUrl() + '/' + model.type + '/' + model.id, method: 'DELETE' }); } }, { key: 'sync', value: function sync(relationship) { var data = this.serialize(this.data()); return this.makePersistRequest({ url: this.getSelfUrl() + '/' + relationship, method: 'PUT', data: data.data.relationships[relationship] }); } // modify query string }, { key: 'with', value: function _with(resourceName) { this.queryBuilder.include(resourceName); return this; } }, { key: 'orderBy', value: function orderBy(column) { var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'asc'; this.queryBuilder.orderBy(column, direction); return this; } }, { key: 'orderByDesc', value: function orderByDesc(column) { return this.orderBy(column, 'desc'); } }, { key: 'where', value: function where(key) { var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var group = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; this.queryBuilder.where(key, value, group); return this; } }, { key: 'filter', value: function filter(_filter) { var group = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; return this.where(_filter, null, group); } }, { key: 'limit', value: function limit(_limit) { return this.where('limit', _limit); } }, { key: 'offset', value: function offset(_offset) { return this.where('offset', _offset); } }, { key: 'select', value: function select(fields) { if ((0, _lodash.isArray)(fields)) { var selectFields = (0, _lodash.clone)(fields); fields = {}; fields[this.resourceName()] = selectFields; } this.queryBuilder.select(fields); return this; } // build model }, { key: 'respond', value: function respond(response) { var data = this.deserialize(response); if (this.isCollection(data)) { return this.resolveCollection(data); } return this.resolveItem(data); } }, { key: 'resolveCollection', value: function resolveCollection(data) { var _this = this; var resolved = {}; if (data.hasOwnProperty('links')) { resolved.links = data.links; } if (data.hasOwnProperty('meta')) { resolved.meta = data.meta; } resolved.data = this.newCollection((0, _lodash.map)(data.data, function (item) { return _this.resolveItem(item); })); return resolved; } }, { key: 'resolveItem', value: function resolveItem(data) { return this.hydrate(data); } }, { key: 'hydrate', value: function hydrate(data) { var _this2 = this; var model = (0, _lodash.clone)(this); model.id = data.id; model.type = data.type; if (data.hasOwnProperty('relationships')) { model.relationshipNames = data.relationships; } if (data.hasOwnProperty('links')) { model.links = data.links; } (0, _lodash.forEach)(model.fields(), function (field) { model[field] = data[field]; }); (0, _lodash.forOwn)(model.dates(), function (format, field) { model[field] = (0, _moment2.default)(data[field]); }); (0, _lodash.forEach)(data.relationships, function (relationship) { var relation = model.relationships()[relationship]; if ((0, _lodash.isUndefined)(relation)) { throw new Error('Sarale: Relationship ' + relationship + ' has not been defined in ' + model.constructor.name + ' model.'); } var fetch = function fetch() { return model.fetchRelation(relationship, data[relationship].links); }; if (_this2.isCollection(data[relationship])) { model[relationship] = (0, _extends3.default)({}, relation.resolveCollection(data[relationship]), { fetch: fetch }); } else if (data[relationship].data) { model[relationship] = relation.resolveItem(data[relationship].data); model[relationship].fetch = fetch; } }); (0, _lodash.forOwn)(model.relationships(), function (relatedModel, relationshipName) { if ((0, _lodash.isUndefined)(model[relationshipName])) { model[relationshipName] = { fetch: function fetch() { return model.fetchRelation(relationshipName); } }; } }); (0, _lodash.forOwn)(model.computed(), function (computation, key) { model[key] = computation(model); }); return model; } // extract data from model }, { key: 'data', value: function data() { var _this3 = this; var data = {}; data.type = this.type; if (this.hasOwnProperty('id')) { data.id = this.id; } if (this.hasOwnProperty('relationshipNames')) { data.relationships = this.relationshipNames; } (0, _lodash.forEach)(this.fields(), function (field) { if (!(0, _lodash.isUndefined)(_this3[field])) { data[field] = _this3[field]; } }); (0, _lodash.forOwn)(this.dates(), function (format, field) { if (!(0, _lodash.isUndefined)(_this3[field])) { data[field] = (0, _moment2.default)(_this3[field]).format(format); } }); (0, _lodash.forEach)(this.relationships(), function (model, relationship) { if (!(0, _lodash.isUndefined)(_this3[relationship]) && !(0, _lodash.isUndefined)(_this3[relationship].data)) { if ((0, _lodash.isArray)(_this3[relationship].data)) { data[relationship] = { data_collection: true, data: (0, _lodash.map)(_this3[relationship].data, function (relation) { return relation.data(); }) }; } else { data[relationship] = { data: _this3[relationship].data() }; } } }); return data; } // helpers }, { key: 'resourceUrl', value: function resourceUrl() { return this.baseUrl() + '/' + this.resourceName() + '/'; } }, { key: 'getSelfUrl', value: function getSelfUrl() { if (this.links.hasOwnProperty('self')) { return this.links.self; } if (!this.hasOwnProperty('id')) { throw new Error('Sarala: Unidentifiable resource exception. ' + this.constructor.name + ' id property is undefined.'); } this.links.self = '' + this.resourceUrl() + this.id; return this.links.self; } }, { key: 'getRelationshipUrl', value: function getRelationshipUrl(relationship) { return this.getSelfUrl() + '/relationships/' + relationship; } }, { key: 'isCollection', value: function isCollection(data) { return data.hasOwnProperty('data_collection') && data.data_collection === true && (0, _lodash.isArray)(data.data); } }, { key: 'deserialize', value: function deserialize(data) { return formatter.deserialize(data); } }, { key: 'serialize', value: function serialize(data) { return formatter.serialize(data); } }, { key: 'selfValidate', value: function selfValidate() { var name = this.resourceName(); if (name === null || !(0, _lodash.isString)(name) || name.length === 0) { throw new Error('Sarale: Resource name not defined in ' + this.constructor.name + ' model. Implement resourceName method in the ' + this.constructor.name + ' model to resolve this error.'); } } }, { key: 'clone', value: function clone() { return (0, _lodash.cloneDeep)(this); } }, { key: 'newCollection', value: function newCollection(data) { return data; } }]); return Model; }(); exports.default = Model;