redink
Version:
RethinkDB model layer
965 lines (804 loc) • 88.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
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; }; }(); /* eslint-disable no-param-reassign */
var _rethinkdb = require('rethinkdb');
var _rethinkdb2 = _interopRequireDefault(_rethinkdb);
var _ResourceArray = require('./ResourceArray');
var _ResourceArray2 = _interopRequireDefault(_ResourceArray);
var _update = require('./constraints/update');
var _utils = require('./utils');
var _queries = require('./queries');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Resource = function () {
/**
* Instantiates a Resource.
*
* @class Resource
* @param {Object} conn - RethinkDB connection object.
* @param {Schema} schema
* @param {Object} record
*/
function Resource(conn, schema, record) {
var _this = this;
_classCallCheck(this, Resource);
if (!conn) {
throw new TypeError('A valid RethinkDB connection is required to instantiate a Resource.');
}
if (!schema) {
throw new TypeError('A valid schema is required to instantiate a Resource.');
}
if (!record) {
throw new TypeError('A valid record is required to instantiate a Resource.');
}
this.conn = conn;
this.schema = schema;
this.id = record.id;
this.meta = record._meta || {};
this.attributes = {};
// FIXME: ensure this clones deeply enough
this.relationships = _extends({}, schema.relationships);
Object.keys(record).forEach(function (field) {
// hydrate attributes
if (schema.hasAttribute(field)) {
_this.attributes[field] = record[field];
return;
}
// hydrate relationships
if (schema.hasRelationship(field)) {
var relationship = _this.relationships[field];
var recordOrRecords = relationship.relation === 'hasMany' ? 'records' : 'record';
_this.relationships[field] = _extends({}, relationship, _defineProperty({}, recordOrRecords, record[field]));
}
});
}
/**
* Returns an attribute.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* user.attribute('name') === 'Dylan'
* });
* ```
*
* @method attribute
* @param {String} attribute
* @return {Any}
*/
_createClass(Resource, [{
key: 'attribute',
value: function attribute(_attribute) {
return this.attributes[_attribute];
}
/**
* Returns a relationship of the resource.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* user.relationship('pets') === {
* type: 'animal',
* field: 'pets',
* schema: Schema,
* relation: 'hasMany',
* inverse: {
* type: 'user',
* relation: 'belongsTo',
* field: 'owner',
* },
* }
*
* user.relationship('teachers') === {
* type: 'teacher',
* field: 'teachers',
* schema: Schema,
* relation: 'hasMany',
* records: [{
* id: '1',
* _archived: false,
* _related: true,
* }, {
* id: '2',
* _archived: false,
* _related: true,
* }],
* inverse: {
* type: 'user',
* relation: 'hasMany',
* field: 'students',
* },
* }
*
* user.relationship('company') === {
* type: 'company',
* field: 'company',
* schema: Schema,
* relation: 'hasOne',
* record: {
* id: '2',
* _archived: false,
* _related: true,
* },
* inverse: {
* type: 'user',
* relation: 'hasMany',
* field: 'employees',
* },
* }
* });
* ```
*
* @method relationship
* @param {String} relationship
* @return {Object}
*/
}, {
key: 'relationship',
value: function relationship(_relationship) {
if (typeof _relationship !== 'string') {
throw new TypeError('Tried calling \'relationship\' method with an argument that was not a String.');
}
return this.relationships[_relationship];
}
/**
* Returns an updated version of the resource.
*
* @async
* @method reload
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource>}
*/
}, {
key: 'reload',
value: function reload() {
var pre = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var post = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var schema = this.schema;
var id = this.id;
var conn = this.conn;
var table = _rethinkdb2.default.table(schema.type);
table = table.get(id);
table = (0, _utils.applyOptions)(table, pre);
table = (0, _utils.mergeRelationships)(table, schema, pre);
table = (0, _utils.applyOptions)(table, post);
return table.run(conn).then(function (record) {
return new Resource(conn, schema, record);
});
}
/**
* Fetches either the `Resource` or `ResourceArray` related to this resource by `relationship`.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* return user.fetch('company');
* }).then(company => {
* // Resource
* });
* ```
*
* @async
* @method fetch
* @param {String} relationship
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource|ResourceArray>}
*/
}, {
key: 'fetch',
value: function fetch(relationship) {
var pre = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var post = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
if (!this.relationship(relationship)) {
return Promise.resolve(null);
}
var conn = this.conn;
var id = this.id;
var _relationship2 = this.relationship(relationship);
var type = _relationship2.type;
var schema = _relationship2.schema;
var relation = _relationship2.relation;
var inverse = _relationship2.inverse;
var relatedRecord = _relationship2.record;
var relatedRecords = _relationship2.records;
var table = _rethinkdb2.default.table(type);
if (relation === 'hasMany') {
if ((0, _utils.requiresIndex)(relation, inverse.relation)) {
table = table.getAll(id, { index: inverse.field });
} else {
table = table.getAll(_rethinkdb2.default.args(relatedRecords.map(function (record) {
return record.id;
})));
}
table = table.coerceTo('array');
} else {
table = table.get(relatedRecord.id);
}
table = (0, _utils.applyOptions)(table, pre);
table = (0, _utils.mergeRelationships)(table, schema, pre);
table = (0, _utils.applyOptions)(table, post);
return table.run(conn).then(function (recordOrRecords) {
if (relation === 'hasMany') return new _ResourceArray2.default(conn, schema, recordOrRecords);
return new Resource(conn, schema, recordOrRecords);
});
}
/**
* Returns the resource pointer(s) based on the multipicity of `relationship`. For example,
* if `relationship` is a M:N relationship, this method will return an array of pointers. If
* `relationship` is a 1:M relationship, this method will return a single pointer.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* user.retrieve('pets') === [{
* id: '1',
* _archived: false,
* _related: false,
* }]
*
* user.retrieve('company') === {
* id: '1',
* _archived: false,
* _related: false,
* }
* });
* ```
*
* @method relationship
* @param {String} relationship
* @return {(Object[]|Object)}
*/
}, {
key: 'retrieve',
value: function retrieve(relationship) {
if (!this.relationship(relationship)) return null;
var _relationship3 = this.relationship(relationship);
var relation = _relationship3.relation;
var record = _relationship3.record;
var records = _relationship3.records;
return relation === 'hasMany' ? records : record;
}
/**
* Updates this resource's attributes.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* return user.update({
* name: 'CJ',
* });
* }).then(user => {
* // Resource
* });
* ```
*
* @async
* @method update
* @param {Object} fields
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource>}
*/
}, {
key: 'update',
value: function update(fields) {
var _this2 = this;
var pre = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var post = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var schema = this.schema;
var id = this.id;
var conn = this.conn;
var type = schema.type;
var table = _rethinkdb2.default.table(type);
var reloadWithOptions = function reloadWithOptions() {
return _this2.reload(pre, post);
};
Object.keys(fields).forEach(function (field) {
if (!schema.hasAttribute(field)) delete fields[field];
});
return table.get(id).update(fields).run(conn).then(reloadWithOptions);
}
/**
* Removes the 'idToRemove' from this resource's 'hasOne' or 'belongsTo' relationship by setting
* the resource pointer's _archived to true.
*
* @async
* @private
* @param {String} idToRemove
* @param {String} field
* @return {Object}
*/
}, {
key: 'archiveRemoveIdFromRecordField',
value: function archiveRemoveIdFromRecordField(idToRemove, field) {
if (typeof idToRemove !== 'string') {
throw new TypeError('Tried calling \'archiveRemoveIdFromRecordField\' with ' + '\'idToRemove\' that was not a string.');
}
if (typeof field !== 'string') {
throw new TypeError('Tried calling \'archiveRemoveIdFromRecordField\' with \'field\' that was not a string.');
}
var type = this.schema.type;
var id = this.id;
var conn = this.conn;
return (0, _queries.archiveRemoveIdFromRecordField)(type, id, field, idToRemove).run(conn);
}
/**
* Removes the 'idToRemove' from each resource, indicated by the array of 'ids', by setting
* each resource pointer's _archived to true.
*
* @async
* @private
* @param {String} type
* @param {String[]} ids
* @param {String} field
* @return {Object}
*/
}, {
key: 'archiveRemoveIdFromManyRecordsField',
value: function archiveRemoveIdFromManyRecordsField(type, ids, field) {
if (typeof type !== 'string') {
throw new TypeError('Tried calling \'archiveRemoveIdFromManyRecordsField\' with ' + '\'type\' that was not a String.');
}
if (!Array.isArray(ids) || !ids.every(function (item) {
return typeof item === 'string';
})) {
throw new TypeError('Tried calling \'archiveRemoveIdFromManyRecordsField\' with ' + '\'ids\' that was not an Array of Strings.');
}
if (typeof field !== 'string') {
throw new TypeError('Tried calling \'archiveRemoveIdFromManyRecordsField\' with ' + '\'field\' that was not a String.');
}
var idToRemove = this.id;
var conn = this.conn;
return (0, _queries.archiveRemoveIdFromManyRecordsField)(type, ids, field, idToRemove).run(conn);
}
/**
* Splices all of the `idsToUpdate` from this resource's 'hasMany' relationship by setting each
* resource pointer's `_archived` to true.
*
* @async
* @private
* @param {String} inverseType
* @param {String} inverseField
* @param {String[]} idsToUpdate
* @param {String} idToSplice
* @return {Object}
*/
}, {
key: 'archiveSpliceIdFromInverseField',
value: function archiveSpliceIdFromInverseField(inverseType, inverseField, idsToUpdate, idToSplice) {
if (typeof inverseType !== 'string') {
throw new TypeError('Tried calling \'archiveSpliceIdFromInverseField\' with ' + '\'inverseType\' that was not a String.');
}
if (typeof inverseField !== 'string') {
throw new TypeError('Tried calling \'archiveSpliceIdFromInverseField\' with ' + '\'inverseField\' that was not a String.');
}
if (!Array.isArray(idsToUpdate) || !idsToUpdate.every(function (item) {
return typeof item === 'string';
})) {
throw new TypeError('Tried calling \'archiveSpliceIdFromInverseField\' with ' + '\'idsToUpdate\' that was not an Array of Strings.');
}
if (typeof idToSplice !== 'string') {
throw new TypeError('Tried calling \'archiveSpliceIdFromInverseField\' with ' + '\'idToSplice\' that was not a String.');
}
return (0, _queries.archiveSpliceIdFromInverseField)(inverseType, inverseField, idsToUpdate, idToSplice).run(this.conn);
}
/**
* Archives this resource and recursively archives its corresponding relationships.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* return user.archive();
* }).then(user => {
* // Resource
* });
* ```
*
* @async
* @method archive
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource>}
*/
}, {
key: 'archive',
value: function archive() {
var _this3 = this;
var pre = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var post = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var type = this.schema.type;
var id = this.id;
var conn = this.conn;
var updateObject = (0, _utils.getArchiveOriginalUpdateObject)(this);
var reloadWithOptions = function reloadWithOptions() {
return _this3.reload(pre, post);
};
return _rethinkdb2.default.table(type).get(id).update(updateObject).run(conn).then(this.recursivelyArchive.bind(this)).then(reloadWithOptions);
}
/**
* Recursively archives this resource's corresponding relationships.
*
* @async
* @private
* @return {Promise}
*/
}, {
key: 'recursivelyArchive',
value: function recursivelyArchive() {
var _this4 = this;
var id = this.id;
return Promise.all(Object.keys(this.relationships).map(function (field) {
var _relationship4 = _this4.relationship(field);
var type = _relationship4.type;
var relation = _relationship4.relation;
var _relationship4$invers = _relationship4.inverse;
var inverseRelation = _relationship4$invers.relation;
var inverseField = _relationship4$invers.field;
var inverseType = _relationship4$invers.type;
if (relation === 'hasMany') {
switch (inverseRelation) {
case 'hasMany':
return _this4.fetch(field).then(function (resources) {
var idsToUpdate = resources.map(function (resource) {
return resource.id;
});
return _this4.archiveSpliceIdFromInverseField.call(_this4, inverseType, inverseField, idsToUpdate, id);
});
case 'belongsTo':
return _this4.fetch(field).then(function (resources) {
return Promise.all(resources.map(function (resource) {
return Promise.all([resource.archive(), resource.archiveRemoveIdFromRecordField(id, inverseField)]);
}));
});
case 'hasOne':
return _this4.fetch(field).then(function (resources) {
var ids = resources.map(function (resource) {
return resource.id;
});
return _this4.archiveRemoveIdFromManyRecordsField.call(_this4, type, ids, inverseField);
});
default:
return true;
}
}
if (relation === 'hasOne') {
switch (inverseRelation) {
case 'hasMany':
return true;
case 'belongsTo':
return _this4.fetch(field).then(function (resource) {
return Promise.all([resource.archive(), resource.archiveRemoveIdFromRecordField(id, inverseField)]);
});
case 'hasOne':
return _this4.fetch(field).then(function (resource) {
return resource.archiveRemoveIdFromRecordField(id, inverseField);
});
default:
return true;
}
}
if (relation === 'belongsTo') {
switch (inverseRelation) {
case 'hasMany':
return true;
case 'belongsTo':
return true;
case 'hasOne':
return _this4.fetch(field).then(function (resource) {
return resource.archiveRemoveIdFromRecordField(id, inverseField);
});
default:
return true;
}
}
return true;
}));
}
/**
* Assigns a resource to this resource's `hasOne` or `belongsTo` relationship identified
* by `relationship`. The `data` argument can either be a Resource or String id.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* return user.put('company', '1');
* }).then(user => {
* // Resource
* });
*
* model('user', 'company').map({
* user(model) {
* return model.fetchResource('1');
* },
* company(model) {
* return model.fetchResource('1');
* },
* }).then(results => {
* const { user, company } = results;
* return user.put('company', company);
* }).then(user => {
* // Resource
* });
* ```
*
* @async
* @method put
* @param {String} relationship
* @param {(String|Resource)} data
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource>}
*/
}, {
key: 'put',
value: function put(relationship, data) {
var _this5 = this;
var pre = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var post = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var relationshipObject = this.relationship(relationship);
var relation = relationshipObject.relation;
var inverse = relationshipObject.inverse;
var field = relationshipObject.field;
var conn = this.conn;
var schema = this.schema;
var id = this.id;
var reloadWithOptions = function reloadWithOptions() {
return _this5.reload(pre, post);
};
var idToPut = void 0;
if (relation !== 'hasOne' && relation !== 'belongsTo') {
throw new TypeError('Tried calling \'put\' on a resource whose \'relationship\' is \'' + relation + '\'. This method ' + 'only works for resources whose \'relationship\' is \'hasOne\' or \'belongsTo\'.');
}
if (!(data instanceof Resource || typeof data === 'string')) {
throw new TypeError('Tried calling \'put\' with \'data\' that was neither a Resource nor a String.');
}
var putData = function putData(isCompliant) {
if (!isCompliant) {
throw new Error('Tried calling \'put\' with \'data\' that violated Redink\'s update constraints.');
}
switch (inverse.relation) {
case 'hasMany':
return (0, _queries.putIdToRecordField)(schema.type, id, field, idToPut).run(conn);
case 'hasOne':
return _rethinkdb2.default.do((0, _queries.putIdToRecordField)(schema.type, id, field, idToPut), (0, _queries.putIdToRecordField)(inverse.type, idToPut, inverse.field, id)).run(conn);
default:
throw new TypeError('Tried calling \'put\' on a resource whose inverse \'relationship\' ' + ('is \'' + inverse.relation + '\'.'));
}
};
// Ensure `id` is an id string
if (typeof data === 'string') idToPut = data;
if (data instanceof Resource) idToPut = data.id;
return (0, _update.isPutCompliant)(relationshipObject, idToPut, conn).then(putData).then(reloadWithOptions);
}
/**
* Removes this resource's `hasOne` relationship. The `relationship` argument must be a
* relationship String.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* return user.remove('company');
* }).then(user => {
* // Resource
* });
* ```
*
* @async
* @method remove
* @param {String} relationship
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource>}
*/
}, {
key: 'remove',
value: function remove(relationship) {
var _this6 = this;
var pre = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var post = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var relationshipObject = this.relationship(relationship);
var relation = relationshipObject.relation;
var inverse = relationshipObject.inverse;
var record = relationshipObject.record;
var field = relationshipObject.field;
var inverseRelation = inverse.relation;
var schema = this.schema;
var id = this.id;
var conn = this.conn;
var reloadWithOptions = function reloadWithOptions() {
return _this6.reload(pre, post);
};
if (relation !== 'hasOne') {
throw new TypeError('Tried calling \'remove\' on a resource whose \'relationship\' is \'' + relation + '\'. This method ' + 'only works for resources whose \'relationship\' is \'hasOne\'.');
}
var removeData = function removeData() {
if (!(0, _update.isRemoveCompliant)(inverseRelation)) {
throw new Error('Tried calling \'remove\' with a relationship that violated Redink\'s update constraints.');
}
switch (inverseRelation) {
case 'hasMany':
return (0, _queries.removeIdFromRecordField)(schema.type, id, field, record.id).run(conn);
case 'hasOne':
return _rethinkdb2.default.do((0, _queries.removeIdFromRecordField)(schema.type, id, field, record.id), (0, _queries.removeIdFromRecordField)(inverse.type, record.id, inverse.field, id)).run(conn);
default:
throw new TypeError('Tried calling \'remove\' on a resource whose inverse \'relationship\' ' + ('is \'' + inverseRelation + '\'.'));
}
};
return removeData().then(reloadWithOptions);
}
/**
* Pushes data to this resource's `relationship`. The `data` can either be a `Resource`,
* `ResourceArray`, array of Strings representing ids, or a String id.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* return user.push('pets', ['1', '2']);
* }).then(user => {
* const newPets = user.relationship('pets'); // will include pets with ids '1' and '2'
* });
*
* model('user', 'animal:pets').map({
* user(model) {
* return model.fetchResource('1');
* },
* pets(model) {
* return model.find({ filter: { name: 'Lassy' } }),
* },
* }).then(results => {
* const { user, pets } = results;
* return user.push('pets', pets);
* }).then(user => {
* const newPets = user.relationship('pets'); // will include pets with name of 'Lassy'
* });
* ```
*
* @async
* @method push
* @param {String} relationship
* @param {(String|String[]|Resource|ResourceArray)} data
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource>}
*/
}, {
key: 'push',
value: function push(relationship, data) {
var _this7 = this;
var pre = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var post = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var relationshipObject = this.relationship(relationship);
var relation = relationshipObject.relation;
var inverse = relationshipObject.inverse;
var field = relationshipObject.field;
var records = relationshipObject.records;
var schema = this.schema;
var id = this.id;
var conn = this.conn;
var reloadWithOptions = function reloadWithOptions() {
return _this7.reload(pre, post);
};
var idsToPush = void 0;
if (relation !== 'hasMany') {
throw new TypeError('Tried calling \'push\' on a resource whose \'relationship\' is \'' + relation + '\'. This method ' + 'only works for resources whose \'relationship\' is \'hasMany\'.');
}
if (!(0, _utils.isDataValidForSpliceAndPush)(data)) {
throw new TypeError('Tried calling \'push\' with \'data\' that was neither a Resource, ResourceArray, ' + 'Array of Strings, nor a String ID.');
}
var checkIsCompliantAndPushData = function checkIsCompliantAndPushData(isCompliant) {
if (!isCompliant) {
throw new Error('Tried calling \'push\' with \'data\' that violated Redink\'s update constraints.');
}
return _rethinkdb2.default.do((0, _queries.pushIdToOriginalField)(schema.type, id, field, records, idsToPush), (0, _queries.pushIdToInverseField)(inverse.type, inverse.field, records, idsToPush, id)).run(conn);
};
// Ensure `ids` is an array of id strings
if (Array.isArray(data)) idsToPush = data;
if (data instanceof _ResourceArray2.default) idsToPush = data.map(function (resource) {
return resource.id;
});
if (typeof data === 'string') idsToPush = [data];
return (0, _update.isPushCompliant)(relationshipObject, idsToPush, conn).then(checkIsCompliantAndPushData).then(reloadWithOptions);
}
/**
* Splices data from the resource's `relationship`. The `data` can either be a `Resource`,
* `ResourceArray`, array of Strings representing ids, or a String id.
*
* ```javascript
* model('user').fetchResource('1').then(user => {
* return user.splice('pets', ['1', '2']);
* }).then(user => {
* const newPets = user.relationship('pets'); // will not include pets with ids '1' and '2'
* });
*
* model('user', 'animal:pets').map({
* user(model) {
* return model.fetchResource('1');
* },
* pets(model) {
* return model.find({ filter: { name: 'Lassy' } }),
* },
* }).then(results => {
* const { user, pets } = results;
* return user.splice('pets', pets);
* }).then(user => {
* const newPets = user.relationship('pets'); // will not include any pets with the name 'Lassy'
* });
* ```
*
* @async
* @method splice
* @param {String} relationship
* @param {(String|String[]|Resource|ResourceArray)} data
* @param {Object} [pre={}] - Critera before merging relationships.
* @param {Object} [post={}] - Critera after merging relationships.
* @return {Promise<Resource>}
*/
}, {
key: 'splice',
value: function splice(relationship, data) {
var _this8 = this;
var pre = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var post = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var relationshipObject = this.relationship(relationship);
var relation = relationshipObject.relation;
var inverse = relationshipObject.inverse;
var field = relationshipObject.field;
var inverseRelation = inverse.relation;
var schema = this.schema;
var id = this.id;
var conn = this.conn;
var reloadWithOptions = function reloadWithOptions() {
return _this8.reload(pre, post);
};
var idsToSplice = void 0;
if (relation !== 'hasMany') {
throw new TypeError('Tried calling \'splice\' on a resource whose \'relationship\' is \'' + relation + '\'. This method ' + 'only works for resources whose \'relationship\' is \'hasMany\'.');
}
if (!(0, _utils.isDataValidForSpliceAndPush)(data)) {
throw new TypeError('Tried calling \'splice\' with \'data\' that was neither a Resource, ResourceArray, ' + 'Array of Strings, nor a String ID.');
}
var spliceData = function spliceData() {
if (!(0, _update.isSpliceCompliant)(inverseRelation)) {
throw new Error('Tried calling \'splice\' with a relationship that violated Redink\'s update constraints.');
}
// Ensure `ids` is an array of id strings
if (Array.isArray(data)) idsToSplice = data;
if (data instanceof _ResourceArray2.default) idsToSplice = data.map(function (resource) {
return resource.id;
});
if (typeof data === 'string') idsToSplice = [data];
return _rethinkdb2.default.do((0, _queries.spliceIdFromOriginalField)(schema.type, field, id, idsToSplice), (0, _queries.spliceIdFromInverseField)(inverse.type, inverse.field, idsToSplice, id)).run(conn);
};
return spliceData().then(reloadWithOptions);
}
/**
* Returns true if this is archived.
*
* @method isArchived
* @return {Boolean}
*/
}, {
key: 'isArchived',
value: function isArchived() {
// eslint-disable-next-line
return this.meta._archived;
}
/**
* Returns a plain object with the `id` key, an `attributes` key, a `relationships` key, and a
* `meta` key.
*
* @method toObject
* @return {Object}
*/
}, {
key: 'toObject',
value: function toObject() {
return {
id: this.id,
attributes: _extends({}, this.attributes),
relationships: _extends({}, this.relationships),
meta: _extends({}, this.meta)
};
}
}]);
return Resource;
}();
exports.default = Resource;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9SZXNvdXJjZS5qcyJdLCJuYW1lcyI6WyJSZXNvdXJjZSIsImNvbm4iLCJzY2hlbWEiLCJyZWNvcmQiLCJUeXBlRXJyb3IiLCJpZCIsIm1ldGEiLCJfbWV0YSIsImF0dHJpYnV0ZXMiLCJyZWxhdGlvbnNoaXBzIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJoYXNBdHRyaWJ1dGUiLCJmaWVsZCIsImhhc1JlbGF0aW9uc2hpcCIsInJlbGF0aW9uc2hpcCIsInJlY29yZE9yUmVjb3JkcyIsInJlbGF0aW9uIiwiYXR0cmlidXRlIiwicHJlIiwicG9zdCIsInRhYmxlIiwidHlwZSIsImdldCIsInJ1biIsInRoZW4iLCJQcm9taXNlIiwicmVzb2x2ZSIsImludmVyc2UiLCJyZWxhdGVkUmVjb3JkIiwicmVsYXRlZFJlY29yZHMiLCJyZWNvcmRzIiwiZ2V0QWxsIiwiaW5kZXgiLCJhcmdzIiwibWFwIiwiY29lcmNlVG8iLCJmaWVsZHMiLCJyZWxvYWRXaXRoT3B0aW9ucyIsInJlbG9hZCIsInVwZGF0ZSIsImlkVG9SZW1vdmUiLCJpZHMiLCJBcnJheSIsImlzQXJyYXkiLCJldmVyeSIsIml0ZW0iLCJpbnZlcnNlVHlwZSIsImludmVyc2VGaWVsZCIsImlkc1RvVXBkYXRlIiwiaWRUb1NwbGljZSIsInVwZGF0ZU9iamVjdCIsInJlY3Vyc2l2ZWx5QXJjaGl2ZSIsImFsbCIsImludmVyc2VSZWxhdGlvbiIsImZldGNoIiwicmVzb3VyY2VzIiwicmVzb3VyY2UiLCJhcmNoaXZlU3BsaWNlSWRGcm9tSW52ZXJzZUZpZWxkIiwiYXJjaGl2ZSIsImFyY2hpdmVSZW1vdmVJZEZyb21SZWNvcmRGaWVsZCIsImFyY2hpdmVSZW1vdmVJZEZyb21NYW55UmVjb3Jkc0ZpZWxkIiwiZGF0YSIsInJlbGF0aW9uc2hpcE9iamVjdCIsImlkVG9QdXQiLCJwdXREYXRhIiwiaXNDb21wbGlhbnQiLCJFcnJvciIsImRvIiwicmVtb3ZlRGF0YSIsImlkc1RvUHVzaCIsImNoZWNrSXNDb21wbGlhbnRBbmRQdXNoRGF0YSIsImlkc1RvU3BsaWNlIiwic3BsaWNlRGF0YSIsIl9hcmNoaXZlZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7cWpCQUFBOzs7QUFDQTs7OztBQUNBOzs7O0FBRUE7O0FBT0E7O0FBUUE7Ozs7Ozs7O0lBWXFCQSxRO0FBQ25COzs7Ozs7OztBQVFBLG9CQUFZQyxJQUFaLEVBQWtCQyxNQUFsQixFQUEwQkMsTUFBMUIsRUFBa0M7QUFBQTs7QUFBQTs7QUFDaEMsUUFBSSxDQUFDRixJQUFMLEVBQVc7QUFDVCxZQUFNLElBQUlHLFNBQUosQ0FBYyxxRUFBZCxDQUFOO0FBQ0Q7O0FBRUQsUUFBSSxDQUFDRixNQUFMLEVBQWE7QUFDWCxZQUFNLElBQUlFLFNBQUosQ0FBYyx1REFBZCxDQUFOO0FBQ0Q7O0FBRUQsUUFBSSxDQUFDRCxNQUFMLEVBQWE7QUFDWCxZQUFNLElBQUlDLFNBQUosQ0FBYyx1REFBZCxDQUFOO0FBQ0Q7O0FBRUQsU0FBS0gsSUFBTCxHQUFZQSxJQUFaO0FBQ0EsU0FBS0MsTUFBTCxHQUFjQSxNQUFkO0FBQ0EsU0FBS0csRUFBTCxHQUFVRixPQUFPRSxFQUFqQjtBQUNBLFNBQUtDLElBQUwsR0FBWUgsT0FBT0ksS0FBUCxJQUFnQixFQUE1Qjs7QUFFQSxTQUFLQyxVQUFMLEdBQWtCLEVBQWxCOztBQUVBO0FBQ0EsU0FBS0MsYUFBTCxnQkFBMEJQLE9BQU9PLGFBQWpDOztBQUVBQyxXQUFPQyxJQUFQLENBQVlSLE1BQVosRUFBb0JTLE9BQXBCLENBQTRCLGlCQUFTO0FBQ25DO0FBQ0EsVUFBSVYsT0FBT1csWUFBUCxDQUFvQkMsS0FBcEIsQ0FBSixFQUFnQztBQUM5QixjQUFLTixVQUFMLENBQWdCTSxLQUFoQixJQUF5QlgsT0FBT1csS0FBUCxDQUF6QjtBQUNBO0FBQ0Q7O0FBRUQ7QUFDQSxVQUFJWixPQUFPYSxlQUFQLENBQXVCRCxLQUF2QixDQUFKLEVBQW1DO0FBQ2pDLFlBQU1FLGVBQWUsTUFBS1AsYUFBTCxDQUFtQkssS0FBbkIsQ0FBckI7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