react-transporter
Advanced tools
Comparing version 0.5.12 to 0.5.13
@@ -7,7 +7,14 @@ 'use strict'; | ||
exports.default = resetStore; | ||
var _getTimestamp = require('../utils/getTimestamp'); | ||
var _getTimestamp2 = _interopRequireDefault(_getTimestamp); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function resetStore() { | ||
return { | ||
type: 'TRANSPORTER_STORE_RESET', | ||
lastReset: new Date().getTime() | ||
lastReset: (0, _getTimestamp2.default)() | ||
}; | ||
} |
@@ -6,3 +6,3 @@ 'use strict'; | ||
}); | ||
exports.selectAdvanced = exports.selectByRoot = exports.selectByRelation = exports.select = exports.ManyLink = exports.Link = exports.query = exports.createContainer = exports.createAsyncContainer = exports.bootstrapper = exports.TransporterClient = exports.TransporterNetwork = exports.resetStore = exports.createQuery = exports.createMutation = undefined; | ||
exports.selectAdvanced = exports.selectByRoot = exports.selectByRelation = exports.select = exports.onError = exports.ManyLink = exports.Link = exports.query = exports.createContainer = exports.createAsyncContainer = exports.bootstrapper = exports.TransporterClient = exports.TransporterNetwork = exports.resetStore = exports.createQuery = exports.createMutation = undefined; | ||
@@ -45,2 +45,4 @@ var _createMutation = require('./actions/createMutation'); | ||
var _createRequest = require('./request/createRequest'); | ||
var _Link = require('./request/Link'); | ||
@@ -83,2 +85,3 @@ | ||
exports.ManyLink = _ManyLink2.default; | ||
exports.onError = _createRequest.onError; | ||
exports.select = _select2.default; | ||
@@ -85,0 +88,0 @@ exports.selectByRelation = _selectByRelation2.default; |
@@ -33,2 +33,6 @@ 'use strict'; | ||
var _getTimestamp = require('../utils/getTimestamp'); | ||
var _getTimestamp2 = _interopRequireDefault(_getTimestamp); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -46,6 +50,2 @@ | ||
var getTimestamp = function getTimestamp() { | ||
return new Date().getTime(); | ||
}; | ||
var resolveES6 = function resolveES6(x) { | ||
@@ -128,3 +128,3 @@ return x != null && (typeof x === 'function' || (typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object') && x.default ? x.default : x; | ||
var loaderState = { | ||
startTime: !isPreload ? getTimestamp() : null, | ||
startTime: !isPreload ? (0, _getTimestamp2.default)() : null, | ||
endTime: null | ||
@@ -325,3 +325,3 @@ }; | ||
// true, a new request will begin and if updatedLoading is false, a request will end. | ||
var time = getTimestamp(); | ||
var time = (0, _getTimestamp2.default)(); | ||
@@ -328,0 +328,0 @@ this.setState(function (state) { |
@@ -9,33 +9,54 @@ 'use strict'; | ||
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; }; | ||
exports.default = createEntitiesReducer; | ||
var _getPosition = require('../utils/getPosition'); | ||
var _applyOptimisticCreate = require('./optimistic/applyOptimisticCreate'); | ||
var _getPosition2 = _interopRequireDefault(_getPosition); | ||
var _applyOptimisticCreate2 = _interopRequireDefault(_applyOptimisticCreate); | ||
var _isAmongEntities = require('./utils/isAmongEntities'); | ||
var _applyOptimisticUpdate = require('./optimistic/applyOptimisticUpdate'); | ||
var _isAmongEntities2 = _interopRequireDefault(_isAmongEntities); | ||
var _applyOptimisticUpdate2 = _interopRequireDefault(_applyOptimisticUpdate); | ||
var _addOptimisticUpdate = require('./utils/addOptimisticUpdate'); | ||
var _applyOptimisticDelete = require('./optimistic/applyOptimisticDelete'); | ||
var _addOptimisticUpdate2 = _interopRequireDefault(_addOptimisticUpdate); | ||
var _applyOptimisticDelete2 = _interopRequireDefault(_applyOptimisticDelete); | ||
var _revertOptimisticUpdate = require('./utils/revertOptimisticUpdate'); | ||
var _revertOptimisticUpdate = require('./optimistic/revertOptimisticUpdate'); | ||
var _revertOptimisticUpdate2 = _interopRequireDefault(_revertOptimisticUpdate); | ||
var _updateValueBeforeRevertingOptimisticUpdate = require('./utils/updateValueBeforeRevertingOptimisticUpdate'); | ||
var _revertOptimisticDelete = require('./optimistic/revertOptimisticDelete'); | ||
var _updateValueBeforeRevertingOptimisticUpdate2 = _interopRequireDefault(_updateValueBeforeRevertingOptimisticUpdate); | ||
var _revertOptimisticDelete2 = _interopRequireDefault(_revertOptimisticDelete); | ||
var _filterOutOptimisticData = require('./optimistic/filterOutOptimisticData'); | ||
var _filterOutOptimisticData2 = _interopRequireDefault(_filterOutOptimisticData); | ||
var _filterOutOptimisticTrash = require('./optimistic/filterOutOptimisticTrash'); | ||
var _filterOutOptimisticTrash2 = _interopRequireDefault(_filterOutOptimisticTrash); | ||
var _EntityMap = require('./EntityMap'); | ||
var _EntityMap2 = _interopRequireDefault(_EntityMap); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function createEntitiesReducer(data) { | ||
function cloneEntityObject(obj) { | ||
var nextObj = {}; | ||
Object.keys(obj).forEach(function (type) { | ||
nextObj[type] = _extends({}, obj[type]); | ||
}); | ||
return nextObj; | ||
} | ||
function createEntitiesReducer(initialData) { | ||
var initialState = { | ||
data: data, | ||
optimistic: { | ||
updates: {}, | ||
deletions: {} | ||
} | ||
data: initialData, | ||
optimistic: {} | ||
}; | ||
@@ -45,37 +66,43 @@ | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState; | ||
var baseAction = arguments[1]; | ||
var action = arguments[1]; | ||
var nextState = JSON.parse(JSON.stringify(state)); | ||
var action = JSON.parse(JSON.stringify(baseAction)); | ||
if (action.type === 'TRANSPORTER_STORE_RESET') { | ||
return initialState; | ||
} | ||
// TRANSPORTER_REQUEST_START | ||
// apply optimistic data | ||
// Apply optimistic data from response. | ||
if (action.type === 'TRANSPORTER_REQUEST_START' && action.optimisticData) { | ||
var nextData = new _EntityMap2.default(cloneEntityObject(state.data)); | ||
var nextOptimistic = new _EntityMap2.default(cloneEntityObject(state.optimistic)); | ||
// insertions/updates | ||
if (action.optimisticData.entities) { | ||
Object.keys(action.optimisticData.entities).forEach(function (type) { | ||
// prerequisites / create (optimistic) type of entities if not present | ||
if (!nextState.data[type]) nextState.data[type] = {}; | ||
if (!nextState.optimistic.updates[type]) nextState.optimistic.updates[type] = {}; | ||
var actionOptimisticEntityMap = new _EntityMap2.default(action.optimisticData.entities); | ||
Object.keys(action.optimisticData.entities[type]).forEach(function (id) { | ||
// prerequisites / create optimistic entity if not present | ||
if (!nextState.optimistic.updates[type][id]) { | ||
nextState.optimistic.updates[type][id] = {}; | ||
} | ||
actionOptimisticEntityMap.forEach(function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 3), | ||
actionOptimisticEntity = _ref2[0], | ||
type = _ref2[1], | ||
id = _ref2[2]; | ||
// add optimistic values | ||
Object.keys(action.optimisticData.entities[type][id]).forEach(function (field) { | ||
var getField = function getField(object) { | ||
if (!object[type] || !object[type][id]) return undefined; | ||
return object[type][id][field]; | ||
}; | ||
var isOptimisticCreate = !nextData.get(type, id); | ||
// add optimistic update value | ||
nextState.optimistic.updates[type][id][field] = (0, _addOptimisticUpdate2.default)(nextState, action, getField); | ||
}); | ||
if (isOptimisticCreate) { | ||
// apply optimistic create | ||
var _applyOptimisticCreat = (0, _applyOptimisticCreate2.default)(action.id, actionOptimisticEntity), | ||
data = _applyOptimisticCreat.data, | ||
optimistic = _applyOptimisticCreat.optimistic; | ||
// temporarily set stored value to optimistic value | ||
nextState.data[type][id] = Object.assign({}, nextState.data[type][id], action.optimisticData.entities[type][id]); | ||
}); | ||
nextData.set(type, id, data); | ||
nextOptimistic.set(type, id, optimistic); | ||
} else { | ||
// apply optimistic update | ||
var _applyOptimisticUpdat = (0, _applyOptimisticUpdate2.default)(action.id, actionOptimisticEntity, nextData.get(type, id), nextOptimistic.get(type, id)), | ||
_data = _applyOptimisticUpdat.data, | ||
_optimistic = _applyOptimisticUpdat.optimistic; | ||
nextData.set(type, id, _data); | ||
nextOptimistic.set(type, id, _optimistic); | ||
} | ||
}); | ||
@@ -86,78 +113,60 @@ } | ||
if (action.optimisticData.trash) { | ||
action.optimisticData.trash.forEach(function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2), | ||
type = _ref2[0], | ||
id = _ref2[1]; | ||
var actionOptimisticTrash = action.optimisticData.trash; | ||
if (nextState.data[type] && nextState.data[type][id]) { | ||
// prerequisites / create optimistic type of entities if not present | ||
if (!nextState.optimistic.deletions[type]) nextState.optimistic.deletions[type] = {}; | ||
actionOptimisticTrash.forEach(function (bla) { | ||
var _bla = _slicedToArray(bla, 2), | ||
type = _bla[0], | ||
id = _bla[1]; | ||
// apply optimistic delete | ||
// add trashed entity to optimistically trashed entities | ||
nextState.optimistic.deletions[type][id] = { | ||
id: action.id, | ||
value: nextState.data[type][id] | ||
}; | ||
// temporarily delete entity | ||
delete nextState.data[type][id]; | ||
} | ||
var _applyOptimisticDelet = (0, _applyOptimisticDelete2.default)(action.id, nextData.get(type, id)), | ||
optimistic = _applyOptimisticDelet.optimistic; | ||
nextData.delete(type, id); | ||
nextOptimistic.set(type, id, optimistic); | ||
}); | ||
} | ||
return { | ||
data: nextData.toSource(), | ||
optimistic: nextOptimistic.toSource() | ||
}; | ||
} | ||
// TRANSPORTER_REQUEST_COMPLETED || TRANSPORTER_REQUEST_ERROR | ||
// revert optimistic data & apply response data for specified fields | ||
if ((action.type === 'TRANSPORTER_REQUEST_COMPLETED' || action.type === 'TRANSPORTER_REQUEST_ERROR') && action.optimisticData) { | ||
// Revert optimistic data and apply response data. | ||
if (action.type === 'TRANSPORTER_REQUEST_COMPLETED' || action.type === 'TRANSPORTER_REQUEST_ERROR') { | ||
var _nextData = new _EntityMap2.default(cloneEntityObject(state.data)); | ||
var _nextOptimistic = new _EntityMap2.default(cloneEntityObject(state.optimistic)); | ||
// insertions/updates | ||
if (action.optimisticData.entities) { | ||
Object.keys(action.optimisticData.entities).forEach(function (type) { | ||
Object.keys(action.optimisticData.entities[type]).forEach(function (id) { | ||
Object.keys(action.optimisticData.entities[type][id]).forEach(function (field) { | ||
var getField = function getField(object) { | ||
if (!object[type] || !object[type][id]) return undefined; | ||
return object[type][id][field]; | ||
}; | ||
if (action.optimisticData && action.optimisticData.entities) { | ||
var actionEntityMap = new _EntityMap2.default(action.data && action.data.entities); | ||
var _actionOptimisticEntityMap = new _EntityMap2.default(action.optimisticData.entities); | ||
// get position of optimistic value & throw error if optimistic value was not found | ||
var position = (0, _getPosition2.default)(action.id, getField(nextState.optimistic.updates).values); | ||
if (position === -1) { | ||
throw new Error('Optimistic value not found.'); | ||
} | ||
_actionOptimisticEntityMap.forEach(function (_ref3) { | ||
var _ref4 = _slicedToArray(_ref3, 3), | ||
actionOptimisticEntity = _ref4[0], | ||
type = _ref4[1], | ||
id = _ref4[2]; | ||
// update stored value | ||
var value = (0, _updateValueBeforeRevertingOptimisticUpdate2.default)(position, nextState, action, getField); | ||
if (value) { | ||
if (!nextState.data[type]) { | ||
nextState.data[type] = {}; | ||
} | ||
var isOptimisticCreate = _nextOptimistic.get(type, id) && _nextOptimistic.get(type, id).type === 'CREATE'; | ||
if (!nextState.data[type][id]) { | ||
nextState.data[type][id] = {}; | ||
} | ||
if (isOptimisticCreate) { | ||
// revert optimistic create | ||
_nextData.delete(type, id); | ||
_nextOptimistic.delete(type, id); | ||
} else { | ||
// revert optimistic update | ||
var _revertOptimisticUpda = (0, _revertOptimisticUpdate2.default)(action.id, actionOptimisticEntity, actionEntityMap.get(type, id), _nextData.get(type, id), _nextOptimistic.get(type, id)), | ||
data = _revertOptimisticUpda.data, | ||
optimistic = _revertOptimisticUpda.optimistic; | ||
nextState.data[type][id][field] = value; | ||
} | ||
// revert optimistic value | ||
nextState.optimistic.updates[type][id][field] = (0, _revertOptimisticUpdate2.default)(position, nextState, action, getField); | ||
if (nextState.optimistic.updates[type][id][field] === undefined) { | ||
delete nextState.optimistic.updates[type][id][field]; | ||
} | ||
// delete value from response if present | ||
if (action.data && action.data.entities && getField(action.data.entities)) { | ||
delete action.data.entities[type][id][field]; | ||
} | ||
}); | ||
// garbage collection | ||
if (Object.keys(nextState.optimistic.updates[type][id]).length === 0) { | ||
delete nextState.optimistic.updates[type][id]; | ||
_nextData.set(type, id, data); | ||
if (optimistic) { | ||
_nextOptimistic.set(type, id, optimistic); | ||
} else { | ||
_nextOptimistic.delete(type, id); | ||
} | ||
}); | ||
// garbage collection | ||
if (Object.keys(nextState.optimistic.updates[type]).length === 0) { | ||
delete nextState.optimistic.updates[type]; | ||
} | ||
@@ -168,49 +177,47 @@ }); | ||
// deletions | ||
if (action.optimisticData.trash) { | ||
action.optimisticData.trash.forEach(function (_ref3) { | ||
var _ref4 = _slicedToArray(_ref3, 2), | ||
type = _ref4[0], | ||
id = _ref4[1]; | ||
if (action.optimisticData && action.optimisticData.trash) { | ||
var actionTrash = action.data && action.data.trash; | ||
var _actionOptimisticTrash = action.optimisticData.trash; | ||
// check if request id is correct | ||
if (nextState.optimistic.deletions[type][id].id !== action.id) { | ||
throw new Error('Optimistic deletion was processed by other request.'); | ||
} | ||
_actionOptimisticTrash.forEach(function (_ref5) { | ||
var _ref6 = _slicedToArray(_ref5, 2), | ||
type = _ref6[0], | ||
id = _ref6[1]; | ||
// check if optimistic deletion is in response too | ||
var position = action.data && action.data.trash ? (0, _isAmongEntities2.default)([type, id], action.data.trash) : -1; | ||
if (position !== -1) { | ||
// if yes -> delete entity from response | ||
delete action.data.trash[position]; | ||
} else { | ||
// if no -> restore entity | ||
// prerequisites / create type of entities if not present | ||
if (!nextState.data[type]) nextState.data[type] = {}; | ||
// revert optimistic delete | ||
var _revertOptimisticDele = (0, _revertOptimisticDelete2.default)(action.id, actionTrash, [type, id], _nextOptimistic.get(type, id)), | ||
data = _revertOptimisticDele.data; | ||
// set entity | ||
nextState.data[type][id] = nextState.optimistic.deletions[type][id].value; | ||
if (data) { | ||
_nextData.set(type, id, data); | ||
} | ||
// finally delete entity from optimistic data | ||
delete nextState.optimistic.deletions[type][id]; | ||
if (Object.keys(nextState.optimistic.deletions[type]).length === 0) { | ||
delete nextState.optimistic.deletions[type]; | ||
} | ||
_nextOptimistic.delete(type, id); | ||
}); | ||
} | ||
} | ||
// TRANSPORTER_REQUEST_COMPLETED | ||
// apply response data | ||
if (action.type === 'TRANSPORTER_REQUEST_COMPLETED') { | ||
// insertions/updates | ||
if (action.data.entities) { | ||
Object.keys(action.data.entities).forEach(function (type) { | ||
// prerequisites / create type of entities if not present | ||
if (!nextState.data[type]) nextState.data[type] = {}; | ||
if (action.data && action.data.entities) { | ||
var _actionEntityMap = new _EntityMap2.default(action.data.entities); | ||
var _actionOptimisticEntityMap2 = new _EntityMap2.default(action.optimisticData && action.optimisticData.entities); | ||
Object.keys(action.data.entities[type]).forEach(function (id) { | ||
// add entity to store | ||
nextState.data[type][id] = Object.assign({}, nextState.data[type][id], action.data.entities[type][id]); | ||
}); | ||
_actionEntityMap.forEach(function (_ref7) { | ||
var _ref8 = _slicedToArray(_ref7, 3), | ||
actionEntity = _ref8[0], | ||
type = _ref8[1], | ||
id = _ref8[2]; | ||
// Set entity data | ||
var data = _nextData.get(type, id); | ||
if (data) { | ||
// Filter out fields that are also in optimistic entity | ||
var fields = (0, _filterOutOptimisticData2.default)(actionEntity, _actionOptimisticEntityMap2.get(type, id)); | ||
fields.forEach(function (field) { | ||
data[field] = actionEntity[field]; | ||
}); | ||
_nextData.set(type, id, data); | ||
} else { | ||
_nextData.set(type, id, actionEntity); | ||
} | ||
}); | ||
@@ -220,28 +227,27 @@ } | ||
// deletions | ||
if (action.data.trash) { | ||
action.data.trash.forEach(function (_ref5) { | ||
var _ref6 = _slicedToArray(_ref5, 2), | ||
type = _ref6[0], | ||
id = _ref6[1]; | ||
if (action.data && action.data.trash) { | ||
var _actionTrash = action.data.trash; | ||
var _actionOptimisticTrash2 = action.optimisticData && action.optimisticData.trash; | ||
// delete entity from store | ||
if (nextState.data[type] && nextState.data[type][id]) { | ||
delete nextState.data[type][id]; | ||
} | ||
// Filter out links that are also in optimistic trash | ||
var links = (0, _filterOutOptimisticTrash2.default)(_actionTrash, _actionOptimisticTrash2); | ||
// Delete entity | ||
links.forEach(function (_ref9) { | ||
var _ref10 = _slicedToArray(_ref9, 2), | ||
type = _ref10[0], | ||
id = _ref10[1]; | ||
_nextData.delete(type, id); | ||
}); | ||
} | ||
} | ||
if (action.type === 'TRANSPORTER_STORE_RESET') { | ||
return { | ||
data: {}, | ||
optimistic: { | ||
updates: {}, | ||
deletions: {} | ||
} | ||
data: _nextData.toSource(), | ||
optimistic: _nextOptimistic.toSource() | ||
}; | ||
} | ||
return nextState; | ||
return state; | ||
}; | ||
} |
@@ -11,8 +11,2 @@ 'use strict'; | ||
var _getPosition = require('../utils/getPosition'); | ||
var _getPosition2 = _interopRequireDefault(_getPosition); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
@@ -36,3 +30,3 @@ | ||
loading: true, | ||
error: null | ||
errors: null | ||
}); | ||
@@ -43,3 +37,5 @@ } | ||
if (action.type === 'TRANSPORTER_REQUEST_COMPLETED') { | ||
var position = (0, _getPosition2.default)(action.id, nextState); | ||
var position = nextState.findIndex(function (request) { | ||
return request.id === action.id; | ||
}); | ||
@@ -54,3 +50,5 @@ nextState[position] = _extends({}, nextState[position], { | ||
if (action.type === 'TRANSPORTER_REQUEST_COMPLETED') { | ||
var _position = (0, _getPosition2.default)(action.id, nextState); | ||
var _position = nextState.findIndex(function (request) { | ||
return request.id === action.id; | ||
}); | ||
@@ -60,3 +58,3 @@ nextState[_position] = _extends({}, nextState[_position], { | ||
loading: false, | ||
error: action.error | ||
errors: action.errors | ||
}); | ||
@@ -63,0 +61,0 @@ } |
@@ -6,25 +6,25 @@ 'use strict'; | ||
}); | ||
exports.default = createRootsReducer; | ||
var _getPosition = require('../utils/getPosition'); | ||
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 _getPosition2 = _interopRequireDefault(_getPosition); | ||
exports.default = createRootsReducer; | ||
var _addOptimisticUpdate = require('./utils/addOptimisticUpdate'); | ||
var _applyOptimisticUpdate = require('./optimistic/applyOptimisticUpdate'); | ||
var _addOptimisticUpdate2 = _interopRequireDefault(_addOptimisticUpdate); | ||
var _applyOptimisticUpdate2 = _interopRequireDefault(_applyOptimisticUpdate); | ||
var _revertOptimisticUpdate = require('./utils/revertOptimisticUpdate'); | ||
var _revertOptimisticUpdate = require('./optimistic/revertOptimisticUpdate'); | ||
var _revertOptimisticUpdate2 = _interopRequireDefault(_revertOptimisticUpdate); | ||
var _filterOutOptimisticData = require('./optimistic/filterOutOptimisticData'); | ||
var _filterOutOptimisticData2 = _interopRequireDefault(_filterOutOptimisticData); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function createRootsReducer(data) { | ||
function createRootsReducer(initialData) { | ||
var initialState = { | ||
data: data, | ||
optimistic: { | ||
updates: {}, | ||
deletions: {} | ||
} | ||
data: initialData, | ||
optimistic: null | ||
}; | ||
@@ -34,69 +34,34 @@ | ||
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState; | ||
var baseAction = arguments[1]; | ||
var action = arguments[1]; | ||
var nextState = JSON.parse(JSON.stringify(state)); | ||
var action = JSON.parse(JSON.stringify(baseAction)); | ||
if (action.type === 'TRANSPORTER_STORE_RESET') { | ||
return initialState; | ||
} | ||
// TRANSPORTER_REQUEST_START | ||
// apply optimistic data | ||
// Apply optimistic data from response. | ||
if (action.type === 'TRANSPORTER_REQUEST_START' && action.optimisticData && action.optimisticData.roots) { | ||
Object.keys(action.optimisticData.roots).forEach(function (root) { | ||
var getRoot = function getRoot(object) { | ||
return object[root]; | ||
}; | ||
// add optimistic update value | ||
nextState.optimistic.updates[root] = (0, _addOptimisticUpdate2.default)(nextState, action, getRoot, true); | ||
}); | ||
// temporarily set stored value to optimistic value | ||
nextState.data = Object.assign({}, nextState.data, action.optimisticData.roots); | ||
// apply optimistic update | ||
return (0, _applyOptimisticUpdate2.default)(action.id, action.optimisticData.roots, state.data, state.optimistic); | ||
} | ||
// TRANSPORTER_REQUEST_COMPLETED || TRANSPORTER_REQUEST_ERROR | ||
// revert optimistic data & apply response data for specified fields | ||
if ((action.type === 'TRANSPORTER_REQUEST_COMPLETED' || action.type === 'TRANSPORTER_REQUEST_ERROR') && action.optimisticData && action.optimisticData.roots) { | ||
Object.keys(action.optimisticData.roots).forEach(function (root) { | ||
var getRoot = function getRoot(object) { | ||
return object[root]; | ||
}; | ||
// Revert optimistic data and apply response data. | ||
if (action.type === 'TRANSPORTER_REQUEST_COMPLETED' || action.type === 'TRANSPORTER_REQUEST_ERROR') { | ||
var nextState = action.optimisticData && action.optimisticData.roots ? (0, _revertOptimisticUpdate2.default)(action.id, action.optimisticData.roots, action.data && action.data.roots, state.data, state.optimistic) : { data: _extends({}, state.data), optimistic: state.optimistic }; | ||
// get position of optimistic value & throw error if optimistic value was not found | ||
var position = (0, _getPosition2.default)(action.id, getRoot(nextState.optimistic.updates).values); | ||
if (position === -1) { | ||
throw new Error('Optimistic value not found.'); | ||
} | ||
if (action.data && action.data.roots) { | ||
// Filter out fields that are also in optimistic entity | ||
var fields = (0, _filterOutOptimisticData2.default)(action.data.roots, action.optimisticData && action.optimisticData.roots); | ||
// revert optimistic value | ||
nextState.optimistic.updates[root] = (0, _revertOptimisticUpdate2.default)(position, state, action, getRoot, true); | ||
if (nextState.optimistic.updates[root] === undefined) { | ||
delete nextState.optimistic.updates[root]; | ||
} | ||
fields.forEach(function (field) { | ||
nextState.data[field] = action.data.roots[field]; | ||
}); | ||
} | ||
// delete value from response if present | ||
if (action.data && action.data.roots && getRoot(action.data.roots)) { | ||
delete action.data.roots[root]; | ||
} | ||
}); | ||
return nextState; | ||
} | ||
// TRANSPORTER_REQUEST_COMPLETED | ||
// apply response data | ||
if (action.type === 'TRANSPORTER_REQUEST_COMPLETED' && action.data.roots) { | ||
// add root to store | ||
nextState.data = Object.assign({}, nextState.data, action.data.roots); | ||
} | ||
if (action.type === 'TRANSPORTER_STORE_RESET') { | ||
return { | ||
data: {}, | ||
optimistic: { | ||
updates: {}, | ||
deletions: {} | ||
} | ||
}; | ||
} | ||
return nextState; | ||
return state; | ||
}; | ||
} |
@@ -6,4 +6,12 @@ 'use strict'; | ||
}); | ||
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; }; | ||
exports.onError = onError; | ||
exports.default = createRequest; | ||
var _WriteStore = require('./WriteStore'); | ||
var _WriteStore2 = _interopRequireDefault(_WriteStore); | ||
var _generateId = require('../utils/generateId'); | ||
@@ -13,6 +21,14 @@ | ||
var _WriteStore = require('./WriteStore'); | ||
var _getTimestamp = require('../utils/getTimestamp'); | ||
var _WriteStore2 = _interopRequireDefault(_WriteStore); | ||
var _getTimestamp2 = _interopRequireDefault(_getTimestamp); | ||
var _TransporterError = require('../errors/TransporterError'); | ||
var _TransporterError2 = _interopRequireDefault(_TransporterError); | ||
var _StoreError = require('../errors/StoreError'); | ||
var _StoreError2 = _interopRequireDefault(_StoreError); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -22,29 +38,82 @@ | ||
var getTimestamp = function getTimestamp() { | ||
return new Date().getTime(); | ||
}; | ||
var customHandleError = void 0; | ||
function onError(callback) { | ||
customHandleError = callback; | ||
} | ||
function makeData(updater, getState, response) { | ||
if (!updater) { | ||
return response; | ||
} | ||
function createRequest(request, fetch) { | ||
var startTime = (0, _getTimestamp2.default)(); | ||
var isMutation = request.type === 'TRANSPORTER_MUTATION'; | ||
var state = getState(); | ||
var requestId = request.id || (0, _generateId2.default)(); | ||
var requestBody = isMutation ? request.mutation.loc.source.body : request.query.loc.source.body; | ||
var store = new _WriteStore2.default(state[TRANSPORTER_STATE], response); | ||
updater(store, response); // TODO only pass in root and trashed ids of response | ||
return store.data; | ||
} | ||
function getStoreData(updater, state, responseData) { | ||
var storeData = responseData ? _extends({}, responseData) : null; | ||
function createRequest(request, fetch) { | ||
// Don't apply roots for mutations. | ||
if (storeData && isMutation) { | ||
delete storeData.roots; | ||
} | ||
if (!updater) { | ||
return storeData; | ||
} | ||
var store = new _WriteStore2.default(state[TRANSPORTER_STATE], storeData); | ||
updater(store, responseData); | ||
return store.toSource(); | ||
} | ||
return function (dispatch, getState) { | ||
// create request id if not present | ||
if (!request.id) request.id = (0, _generateId2.default)(); | ||
var startTime = getTimestamp(); | ||
var storeData = request.type === 'TRANSPORTER_MUTATION' ? makeData(request.optimisticUpdater, getState) : {}; | ||
var optimisticData = request.type === 'TRANSPORTER_MUTATION' ? storeData : null; | ||
function handleError(error, data, optimisticData) { | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_ERROR', | ||
id: requestId, | ||
endTime: (0, _getTimestamp2.default)(), | ||
optimisticData: optimisticData, | ||
data: data, | ||
error: { | ||
type: error.type, | ||
message: error.message, | ||
data: error.data | ||
} | ||
}); | ||
if (customHandleError) { | ||
customHandleError(error); | ||
} | ||
return Promise.reject(error); | ||
} | ||
// Create optimisticData if request is of type mutation. | ||
var optimisticData = void 0; | ||
if (isMutation) { | ||
try { | ||
optimisticData = getStoreData(request.optimisticUpdater, getState()); | ||
} catch (error) { | ||
// Error #1: Something went wrong while applying optimistic updater. | ||
if (error.name === 'StoreError') { | ||
var transporterError = new _TransporterError2.default('StoreError', 'Request failed (StoreError)', { | ||
error: error.message | ||
}); | ||
if (customHandleError) { | ||
customHandleError(transporterError); | ||
} | ||
return Promise.reject(transporterError); | ||
} | ||
throw error; | ||
} | ||
} | ||
// Start request. | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_START', | ||
id: request.id, | ||
id: requestId, | ||
startTime: startTime, | ||
@@ -54,77 +123,68 @@ optimisticData: optimisticData | ||
var queryBody = request.type === 'TRANSPORTER_MUTATION' ? request.mutation.loc.source.body : request.query.loc.source.body; | ||
return fetch(requestBody, request.variables).then(function (result) { | ||
return result.json().then(function (response) { | ||
// Error #2: Http error code detected, throw error. | ||
if (!result.ok) { | ||
return handleError(new _TransporterError2.default('HttpError', 'Request failed (HttpError - ' + result.status + ')', response), null, optimisticData); | ||
} | ||
// dispatch query | ||
return fetch(queryBody, request.variables).then(function (result) { | ||
return result.json().then(function (responseData) { | ||
var state = getState(); | ||
// Only apply response if store was not reset in the meantime | ||
// Error #3: In the meantime the store was resetted, so do not apply response. | ||
if (state[TRANSPORTER_STATE].info.lastReset >= startTime) { | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_ERROR', | ||
id: request.id, | ||
endTime: new Date().getTime(), | ||
// We don't need to rollback optimisticData here | ||
optimisticData: {}, | ||
error: 'Store reset after request was started.' | ||
}); | ||
var error = new _StoreError2.default('Store reset after request was started.'); | ||
throw new Error(); | ||
return handleError(new _TransporterError2.default('StoreError', 'Request failed (StoreError)', { | ||
error: error.message | ||
}), null, null); | ||
} | ||
// Response has errors | ||
if (responseData.errors && responseData.errors.length > 0) { | ||
// Log and throw GraphQL error(s) | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_ERROR', | ||
id: request.id, | ||
endTime: getTimestamp(), | ||
optimisticData: optimisticData, | ||
error: responseData.errors | ||
// Error #4: Response has GraphQL errors, throw error. | ||
if (response.errors) { | ||
response.errors.forEach(function (error) { | ||
// eslint-disable-next-line no-console | ||
console.error('GraphQLError: ' + error.message); | ||
}); | ||
throw responseData.errors; | ||
return handleError(new _TransporterError2.default('GraphQLError', 'Request failed (GraphQLError)', { | ||
errors: response.errors | ||
}), response.data, optimisticData); | ||
} | ||
// Response is okay | ||
try { | ||
var data = makeData(request.updater, getState, responseData.data); | ||
// Response is okay. | ||
var data = void 0; | ||
if (response.data) { | ||
try { | ||
data = getStoreData(request.updater, state, response.data); | ||
} catch (error) { | ||
// Error #5: Something went wrong while applying updater. | ||
if (error.name === 'StoreError') { | ||
return handleError(new _TransporterError2.default('StoreError', 'Request failed (StoreError)', { | ||
error: error.message | ||
}), response.data, optimisticData); | ||
} | ||
// Try to add response to store | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_COMPLETED', | ||
id: request.id, | ||
endTime: getTimestamp(), | ||
optimisticData: optimisticData, | ||
data: data | ||
}); | ||
} catch (error) { | ||
// Log and throw internal error | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_ERROR', | ||
id: request.id, | ||
endTime: getTimestamp(), | ||
optimisticData: optimisticData, | ||
error: 'Internal error' | ||
}); | ||
throw error; | ||
throw error; | ||
} | ||
} | ||
return responseData; | ||
// Complete request. | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_COMPLETED', | ||
id: requestId, | ||
endTime: (0, _getTimestamp2.default)(), | ||
optimisticData: optimisticData, | ||
data: data | ||
}); | ||
return response.data; | ||
}, function (error) { | ||
// Error #6: Found JSON parsing error. | ||
return handleError(new _TransporterError2.default('JsonError', error.message + ' (JsonError)'), null, optimisticData); | ||
}); | ||
}, function (error) { | ||
// Something else went wrong | ||
dispatch({ | ||
type: 'TRANSPORTER_REQUEST_ERROR', | ||
id: request.id, | ||
endTime: getTimestamp(), | ||
optimisticData: optimisticData, | ||
error: error | ||
}); | ||
throw error; | ||
// Error #7: Some network error occured. | ||
return handleError(new _TransporterError2.default('NetworkError', error.message + ' (NetworkError)'), null, optimisticData); | ||
}); | ||
}; | ||
} |
@@ -9,6 +9,10 @@ 'use strict'; | ||
var _getName = require('../utils/getName'); | ||
exports.getFieldValue = getFieldValue; | ||
exports.prepareFieldValue = prepareFieldValue; | ||
exports.validateFieldValue = validateFieldValue; | ||
var _getName2 = _interopRequireDefault(_getName); | ||
var _getKeyName = require('../utils/getKeyName'); | ||
var _getKeyName2 = _interopRequireDefault(_getKeyName); | ||
var _isConnection = require('../utils/isConnection'); | ||
@@ -22,6 +26,2 @@ | ||
var _getRawLink = require('./utils/getRawLink'); | ||
var _getRawLink2 = _interopRequireDefault(_getRawLink); | ||
var _Link = require('./Link'); | ||
@@ -35,10 +35,6 @@ | ||
var _makeRequestError = require('./makeRequestError'); | ||
var _StoreError = require('../errors/StoreError'); | ||
var _makeRequestError2 = _interopRequireDefault(_makeRequestError); | ||
var _StoreError2 = _interopRequireDefault(_StoreError); | ||
var _isDate = require('./utils/isDate'); | ||
var _isDate2 = _interopRequireDefault(_isDate); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -48,10 +44,38 @@ | ||
function prepareValue(value, entity, name) { | ||
var returnValue = typeof value === 'function' ? value(entity.get(name)) : value; | ||
function isDate(obj) { | ||
return Object.prototype.toString.call(obj) === '[object Date]'; | ||
} | ||
function getCurrentFieldValue(name, value, originalValue, optimistic) { | ||
if (value !== undefined) { | ||
return value; | ||
} | ||
if (optimistic && optimistic.type === 'UPDATE' && optimistic.data[name] !== undefined) { | ||
return optimistic.data[name].originalValue; | ||
} | ||
return originalValue; | ||
} | ||
function getFieldValue(name, value, originalValue, optimistic) { | ||
var currentValue = getCurrentFieldValue(name, value, originalValue, optimistic); | ||
// return connection value | ||
if ((0, _isConnection2.default)(currentValue)) { | ||
return (0, _isManyLink2.default)(currentValue.link) ? new _ManyLink2.default(currentValue) : new _Link2.default(currentValue); | ||
} | ||
// return scalar value | ||
return currentValue; | ||
} | ||
function prepareFieldValue(name, value, currentValue) { | ||
var returnValue = typeof value === 'function' ? value(currentValue) : value; | ||
if ((0, _isConnection2.default)(returnValue)) { | ||
return (0, _getRawLink2.default)(returnValue); | ||
return returnValue.toSource(); | ||
} | ||
if ((0, _isDate2.default)(returnValue)) { | ||
if (isDate(returnValue)) { | ||
return returnValue.toISOString(); | ||
@@ -63,18 +87,30 @@ } | ||
function checkValue(value, originalValue, variables) { | ||
function validateFieldValue(name, value, currentValue, link) { | ||
if (currentValue === undefined) { | ||
return; | ||
} | ||
// check field type | ||
if ((0, _isConnection2.default)(originalValue) && !(0, _isConnection2.default)(value)) { | ||
throw (0, _makeRequestError2.default)('WRONG_CONNECTION_FIELD_VALUE'); | ||
if ((0, _isConnection2.default)(currentValue) && !(0, _isConnection2.default)(value)) { | ||
var error = 'Cannot set field "' + name + '", because it needs a scalar value, not a connection.'; | ||
throw new _StoreError2.default(error, link); | ||
} | ||
if (!(0, _isConnection2.default)(originalValue) && (0, _isConnection2.default)(value)) { | ||
throw (0, _makeRequestError2.default)('WRONG_SCALAR_FIELD_VALUE', variables); | ||
if (!(0, _isConnection2.default)(currentValue) && (0, _isConnection2.default)(value)) { | ||
var _error = 'Cannot set field "' + name + '", because it needs a connection, not a scalar value.'; | ||
throw new _StoreError2.default(_error, link); | ||
} | ||
// check connection type | ||
if ((0, _isConnection2.default)(originalValue) && (0, _isConnection2.default)(value)) { | ||
if ((0, _isManyLink2.default)(originalValue.link) && !(0, _isManyLink2.default)(value.link)) { | ||
throw (0, _makeRequestError2.default)('WRONG_CONNECTION_MANYLINK_FIELD_VALUE', variables); | ||
if ((0, _isConnection2.default)(currentValue) && (0, _isConnection2.default)(value)) { | ||
if ((0, _isManyLink2.default)(currentValue.link) && !(0, _isManyLink2.default)(value.link)) { | ||
var _error2 = 'Cannot set field "' + name + '", because it is of type ManyLink, not Link.'; | ||
throw new _StoreError2.default(_error2, link); | ||
} | ||
if (!(0, _isManyLink2.default)(originalValue.link) && (0, _isManyLink2.default)(value.link)) { | ||
throw (0, _makeRequestError2.default)('WRONG_CONNECTION_LINK_FIELD_VALUE', variables); | ||
if (!(0, _isManyLink2.default)(currentValue.link) && (0, _isManyLink2.default)(value.link)) { | ||
var _error3 = 'Cannot set field "' + name + '", because it is of type Link, not ManyLink.'; | ||
throw new _StoreError2.default(_error3, link); | ||
} | ||
@@ -85,3 +121,3 @@ } | ||
var Entity = function () { | ||
function Entity(type, id, originalValues) { | ||
function Entity(type, id, originalValues, optimistic) { | ||
_classCallCheck(this, Entity); | ||
@@ -91,4 +127,7 @@ | ||
this.id = id; | ||
this.originalValues = originalValues; | ||
this.originalValues = originalValues || {}; | ||
this.values = {}; | ||
this.optimistic = optimistic; | ||
} | ||
@@ -99,16 +138,19 @@ | ||
value: function get(name) { | ||
if (this.values[name] === undefined && this.originalValues && this.originalValues[name] === undefined) { | ||
throw (0, _makeRequestError2.default)('MISSING_FIELD', { type: this.type, id: this.id, name: name }); | ||
if (this.values[name] === undefined && this.originalValues[name] === undefined) { | ||
var error = 'Cannot get field "' + name + '", because it does not exist.'; | ||
throw new _StoreError2.default(error, [this.type, this.id]); | ||
} | ||
// get new or original value | ||
var value = this.values[name] || this.originalValues[name]; | ||
return getFieldValue(name, this.values[name], this.originalValues[name], this.optimistic); | ||
} | ||
// return connection value | ||
if ((0, _isConnection2.default)(value)) { | ||
return (0, _isManyLink2.default)(value.link) ? new _ManyLink2.default(value) : new _Link2.default(value); | ||
} | ||
// Alias for set, because of flowtype problem. | ||
// return scalar value | ||
return value; | ||
}, { | ||
key: 'setDistinct', | ||
value: function setDistinct(rawName) { | ||
var rawValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; | ||
this.set(rawName, rawValue); | ||
} | ||
@@ -120,9 +162,7 @@ }, { | ||
var name = (0, _getName2.default)(rawName); | ||
var value = prepareValue(rawValue, this, name); | ||
var name = (0, _getKeyName2.default)(rawName); | ||
var currentValue = getFieldValue(name, this.values[name], this.originalValues[name], this.optimistic); | ||
var value = prepareFieldValue(name, rawValue, currentValue); | ||
// check correct type | ||
if (this.originalValues && this.originalValues[name]) { | ||
checkValue(value, this.originalValues[name], { type: this.type, id: this.id, name: name }); | ||
} | ||
validateFieldValue(name, value, currentValue, [this.type, this.id]); | ||
@@ -137,8 +177,6 @@ this.values[name] = value; | ||
Object.keys(values).forEach(function (name) { | ||
var value = prepareValue(values[name], _this, name); | ||
var currentValue = getFieldValue(name, _this.values[name], _this.originalValues[name], _this.optimistic); | ||
var value = prepareFieldValue(name, values[name], currentValue); | ||
// check correct type | ||
if (_this.originalValues && _this.originalValues[name]) { | ||
checkValue(value, _this.originalValues[name], { type: _this.type, id: _this.id, name: name }); | ||
} | ||
validateFieldValue(name, value, currentValue, [_this.type, _this.id]); | ||
@@ -145,0 +183,0 @@ _this.values[name] = value; |
@@ -47,2 +47,10 @@ 'use strict'; | ||
} | ||
}, { | ||
key: 'toSource', | ||
value: function toSource() { | ||
return { | ||
link: this.link, | ||
meta: this.meta | ||
}; | ||
} | ||
}]); | ||
@@ -49,0 +57,0 @@ |
@@ -9,25 +9,36 @@ 'use strict'; | ||
var _getTypeIds = require('./utils/getTypeIds'); | ||
var _isConnection = require('../utils/isConnection'); | ||
var _getTypeIds2 = _interopRequireDefault(_getTypeIds); | ||
var _isConnection2 = _interopRequireDefault(_isConnection); | ||
var _prependEntities = require('./utils/prependEntities'); | ||
var _isString = require('../utils/isString'); | ||
var _prependEntities2 = _interopRequireDefault(_prependEntities); | ||
var _isString2 = _interopRequireDefault(_isString); | ||
var _appendEntities = require('./utils/appendEntities'); | ||
var _isSameEntity = require('../utils/isSameEntity'); | ||
var _appendEntities2 = _interopRequireDefault(_appendEntities); | ||
var _isSameEntity2 = _interopRequireDefault(_isSameEntity); | ||
var _detachEntities = require('./utils/detachEntities'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _detachEntities2 = _interopRequireDefault(_detachEntities); | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
var _isConnection = require('../utils/isConnection'); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var _isConnection2 = _interopRequireDefault(_isConnection); | ||
function getLinks(type, idOrIds) { | ||
if ((0, _isString2.default)(type)) { | ||
if ((0, _isString2.default)(idOrIds)) { | ||
// case 1) one type, one id | ||
return [[type, idOrIds]]; | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// case 2) one type, many ids | ||
return idOrIds.map(function (id) { | ||
return [type, id]; | ||
}); | ||
} | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
// case 3) many types, many ids | ||
return type; | ||
} | ||
@@ -42,6 +53,5 @@ var ManyLink = function () { | ||
this.link = type.link; | ||
return; | ||
} else { | ||
this.link = type ? getLinks(type) : []; | ||
} | ||
this.link = type ? (0, _getTypeIds2.default)(type) : []; | ||
} | ||
@@ -52,3 +62,4 @@ | ||
value: function prepend(type, idOrIds) { | ||
this.link = (0, _prependEntities2.default)((0, _getTypeIds2.default)(type, idOrIds), this.link); | ||
this.link = [].concat(_toConsumableArray(getLinks(type, idOrIds)), _toConsumableArray(this.link)); | ||
return this; | ||
@@ -59,3 +70,4 @@ } | ||
value: function append(type, idOrIds) { | ||
this.link = (0, _appendEntities2.default)((0, _getTypeIds2.default)(type, idOrIds), this.link); | ||
this.link = [].concat(_toConsumableArray(this.link), _toConsumableArray(getLinks(type, idOrIds))); | ||
return this; | ||
@@ -66,3 +78,7 @@ } | ||
value: function syncPrepend(type, idOrIds) { | ||
this.link = (0, _prependEntities2.default)((0, _getTypeIds2.default)(type, idOrIds), this.link, true); | ||
var inputLinks = getLinks(type, idOrIds); | ||
var filteredLinks = this.eliminate(inputLinks); | ||
this.link = [].concat(_toConsumableArray(inputLinks), _toConsumableArray(filteredLinks)); | ||
return this; | ||
@@ -73,3 +89,7 @@ } | ||
value: function syncAppend(type, idOrIds) { | ||
this.link = (0, _appendEntities2.default)((0, _getTypeIds2.default)(type, idOrIds), this.link, true); | ||
var inputLinks = getLinks(type, idOrIds); | ||
var filteredLinks = this.eliminate(inputLinks); | ||
this.link = [].concat(_toConsumableArray(filteredLinks), _toConsumableArray(inputLinks)); | ||
return this; | ||
@@ -80,6 +100,22 @@ } | ||
value: function detach(type, idOrIds) { | ||
this.link = (0, _detachEntities2.default)((0, _getTypeIds2.default)(type, idOrIds), this.link); | ||
var inputLinks = getLinks(type, idOrIds); | ||
if (inputLinks === null) { | ||
this.link = []; | ||
} else { | ||
this.link = this.eliminate(inputLinks); | ||
} | ||
return this; | ||
} | ||
}, { | ||
key: 'eliminate', | ||
value: function eliminate(inputLinks) { | ||
return this.link.filter(function (link) { | ||
return !inputLinks.some(function (inputLink) { | ||
return (0, _isSameEntity2.default)(link, inputLink); | ||
}); | ||
}); | ||
} | ||
}, { | ||
key: 'setMeta', | ||
@@ -94,2 +130,10 @@ value: function setMeta(meta) { | ||
} | ||
}, { | ||
key: 'toSource', | ||
value: function toSource() { | ||
return { | ||
link: this.link, | ||
meta: this.meta | ||
}; | ||
} | ||
}]); | ||
@@ -96,0 +140,0 @@ |
@@ -9,60 +9,57 @@ 'use strict'; | ||
var _getName = require('../utils/getName'); | ||
var _getKeyName = require('../utils/getKeyName'); | ||
var _getName2 = _interopRequireDefault(_getName); | ||
var _getKeyName2 = _interopRequireDefault(_getKeyName); | ||
var _isConnection = require('../utils/isConnection'); | ||
var _Entity = require('./Entity'); | ||
var _isConnection2 = _interopRequireDefault(_isConnection); | ||
var _Entity2 = _interopRequireDefault(_Entity); | ||
var _isManyLink = require('../utils/isManyLink'); | ||
var _StoreError = require('../errors/StoreError'); | ||
var _isManyLink2 = _interopRequireDefault(_isManyLink); | ||
var _StoreError2 = _interopRequireDefault(_StoreError); | ||
var _getRawLink = require('./utils/getRawLink'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _getRawLink2 = _interopRequireDefault(_getRawLink); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var _Link = require('./Link'); | ||
function validateInsert(data, optimistic, link) { | ||
if (data) { | ||
var error = 'Cannot insert entity, because entity already exists.'; | ||
var _Link2 = _interopRequireDefault(_Link); | ||
throw new _StoreError2.default(error, link); | ||
} | ||
var _ManyLink = require('./ManyLink'); | ||
if (optimistic && optimistic.type === 'DELETE') { | ||
var _error = 'Cannot perform insert on optimistically deleted entity.'; | ||
var _ManyLink2 = _interopRequireDefault(_ManyLink); | ||
throw new _StoreError2.default(_error, link); | ||
} | ||
} | ||
var _Entity = require('./Entity'); | ||
function validateUpdate(data, optimistic, link) { | ||
if (!data) { | ||
var error = optimistic && optimistic.type === 'DELETE' ? 'Cannot perform update on optimistically deleted entity.' : 'Cannot update entity, because entity does not exist.'; | ||
var _Entity2 = _interopRequireDefault(_Entity); | ||
throw new _StoreError2.default(error, link); | ||
} | ||
var _makeRequestError = require('./makeRequestError'); | ||
if (optimistic && optimistic.type === 'CREATE') { | ||
var _error2 = 'Cannot perform update on optimistically created entity.'; | ||
var _makeRequestError2 = _interopRequireDefault(_makeRequestError); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function entityExists(type, id, storedEntities, data) { | ||
return storedEntities[type] && storedEntities[type][id] || data.entities[type] && data.entities[type][id]; | ||
throw new _StoreError2.default(_error2, link); | ||
} | ||
} | ||
function prepareRootValue(value, originalValue) { | ||
return (0, _getRawLink2.default)(typeof value === 'function' ? value((0, _isManyLink2.default)(originalValue.link) ? new _ManyLink2.default(originalValue) : new _Link2.default(originalValue)) : value); | ||
} | ||
function validateDelete(data, optimistic, link) { | ||
if (!data) { | ||
var error = optimistic && optimistic.type === 'DELETE' ? 'Cannot perform delete on optimistically deleted entity.' : 'Cannot delete entity, because entity does not exist.'; | ||
function checkRootValue(value, originalValue, variables) { | ||
// check if value is connection value | ||
if (!value || !(0, _isConnection2.default)(value)) { | ||
throw (0, _makeRequestError2.default)('WRONG_ROOT_VALUE'); | ||
throw new _StoreError2.default(error, link); | ||
} | ||
// check connection type | ||
if ((0, _isConnection2.default)(originalValue)) { | ||
if ((0, _isManyLink2.default)(originalValue.link) && !(0, _isManyLink2.default)(value.link)) { | ||
throw (0, _makeRequestError2.default)('WRONG_ROOT_MANYLINK_VALUE', variables); | ||
} | ||
if (!(0, _isManyLink2.default)(originalValue.link) && (0, _isManyLink2.default)(value.link)) { | ||
throw (0, _makeRequestError2.default)('WRONG_ROOT_LINK_VALUE', variables); | ||
} | ||
if (optimistic && optimistic.type === 'CREATE') { | ||
var _error3 = 'Cannot perform delete on optimistically created entity.'; | ||
throw new _StoreError2.default(_error3, link); | ||
} | ||
@@ -72,9 +69,9 @@ } | ||
var WriteStore = function () { | ||
function WriteStore(state, response) { | ||
function WriteStore(state, data) { | ||
_classCallCheck(this, WriteStore); | ||
this.state = state; | ||
this.data = response || { | ||
entities: {}, | ||
roots: {}, | ||
this.data = { | ||
entities: data && data.entities || {}, | ||
roots: data && data.roots || {}, | ||
trash: [] | ||
@@ -87,6 +84,7 @@ }; | ||
value: function insert(type, id, setAttributes) { | ||
if (entityExists(type, id, this.state.entities.data, this.data)) { | ||
throw (0, _makeRequestError2.default)('EXISTING_ENTITY_INSERT', { type: type, id: id }); | ||
} | ||
var data = this.getData(type, id); | ||
var optimistic = this.getOptimistic(type, id); | ||
validateInsert(data, optimistic, [type, id]); | ||
var entity = new _Entity2.default(type, id); | ||
@@ -101,8 +99,9 @@ | ||
value: function update(type, id, setAttributes) { | ||
if (!entityExists(type, id, this.state.entities.data, this.data)) { | ||
throw (0, _makeRequestError2.default)('MISSING_ENTITY_UDPATE', { type: type, id: id }); | ||
} | ||
var data = this.getData(type, id); | ||
var optimistic = this.getOptimistic(type, id); | ||
var entity = new _Entity2.default(type, id, this.state.entities.data[type][id]); | ||
validateUpdate(data, optimistic, [type, id]); | ||
var entity = new _Entity2.default(type, id, data, optimistic); | ||
setAttributes(entity); | ||
@@ -116,6 +115,7 @@ if (!this.data.entities[type]) this.data.entities[type] = {}; | ||
value: function _delete(type, id) { | ||
if (!entityExists(type, id, this.state.entities.data, this.data)) { | ||
throw (0, _makeRequestError2.default)('MISSING_ENTITY_UDPATE', { type: type, id: id }); | ||
} | ||
var data = this.getData(type, id); | ||
var optimistic = this.getOptimistic(type, id); | ||
validateDelete(data, optimistic, [type, id]); | ||
this.data.trash.push([type, id]); | ||
@@ -126,10 +126,46 @@ } | ||
value: function setRoot(rawName, rawValue) { | ||
var name = (0, _getName2.default)(rawName); | ||
var name = (0, _getKeyName2.default)(rawName); | ||
var value = prepareRootValue(rawValue, this.state.roots.data[name]); | ||
var currentValue = (0, _Entity.getFieldValue)(name, this.data.roots[name], this.state.roots[name], this.state.roots.optimistic); | ||
var value = (0, _Entity.prepareFieldValue)(name, rawValue, currentValue); | ||
checkRootValue(value, this.state.roots.data[name], { name: name }); | ||
(0, _Entity.validateFieldValue)(name, value, currentValue, 'root'); | ||
this.data.roots[name] = value; | ||
} | ||
}, { | ||
key: 'getData', | ||
value: function getData(type, id) { | ||
var data = this.state.entities.data; | ||
return data[type] && data[type][id]; | ||
} | ||
}, { | ||
key: 'getOptimistic', | ||
value: function getOptimistic(type, id) { | ||
var optimistic = this.state.entities.optimistic; | ||
return optimistic[type] && optimistic[type][id]; | ||
} | ||
}, { | ||
key: 'toSource', | ||
value: function toSource() { | ||
var obj = {}; | ||
if (Object.keys(this.data.entities).length !== 0) { | ||
obj.entities = this.data.entities; | ||
} | ||
if (Object.keys(this.data.roots).length !== 0) { | ||
obj.roots = this.data.roots; | ||
} | ||
if (this.data.trash.length !== 0) { | ||
obj.trash = this.data.trash; | ||
} | ||
return obj; | ||
} | ||
}]); | ||
@@ -136,0 +172,0 @@ |
@@ -13,9 +13,9 @@ 'use strict'; | ||
var _makeSelectorError = require('./makeSelectorError'); | ||
var _StoreError = require('../errors/StoreError'); | ||
var _makeSelectorError2 = _interopRequireDefault(_makeSelectorError); | ||
var _StoreError2 = _interopRequireDefault(_StoreError); | ||
var _getName = require('../utils/getName'); | ||
var _getKeyName = require('../utils/getKeyName'); | ||
var _getName2 = _interopRequireDefault(_getName); | ||
var _getKeyName2 = _interopRequireDefault(_getKeyName); | ||
@@ -43,3 +43,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
if (!this.state.entities.data[type] || !this.state.entities.data[type][id]) { | ||
throw (0, _makeSelectorError2.default)('MISSING_ENTITY', { type: type, id: id }); | ||
throw new _StoreError2.default('Selected entity not found.', [type, id]); | ||
} | ||
@@ -52,6 +52,6 @@ | ||
value: function selectByRoot(rawName, query) { | ||
var name = (0, _getName2.default)(rawName); | ||
var name = (0, _getKeyName2.default)(rawName); | ||
if (!this.state.roots.data[name]) { | ||
throw (0, _makeSelectorError2.default)('MISSING_ROOT', { name: name }); | ||
throw new _StoreError2.default('Selected root \'' + name + '\' not found.', 'root'); | ||
} | ||
@@ -66,6 +66,6 @@ | ||
value: function selectByRelation(type, id, rawName, query) { | ||
var name = (0, _getName2.default)(rawName); | ||
var name = (0, _getKeyName2.default)(rawName); | ||
if (!this.state.entities.data[type] || !this.state.entities.data[type][id] || !this.state.entities.data[type][id][name]) { | ||
throw (0, _makeSelectorError2.default)('MISSING_RELATION', { type: type, id: id, name: name }); | ||
throw new _StoreError2.default('Selected relation \'' + name + '\' not found.', [type, id]); | ||
} | ||
@@ -72,0 +72,0 @@ |
@@ -9,22 +9,24 @@ 'use strict'; | ||
var _isManyLink = require('../utils/isManyLink'); | ||
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 _isManyLink2 = _interopRequireDefault(_isManyLink); | ||
var _getKeyName = require('../utils/getKeyName'); | ||
var _compareValues = require('./utils/compareValues'); | ||
var _getKeyName2 = _interopRequireDefault(_getKeyName); | ||
var _compareValues2 = _interopRequireDefault(_compareValues); | ||
var _isString = require('../utils/isString'); | ||
var _formatData = require('./utils/formatData'); | ||
var _isString2 = _interopRequireDefault(_isString); | ||
var _formatData2 = _interopRequireDefault(_formatData); | ||
var _isConnection = require('../utils/isConnection'); | ||
var _getRelationData = require('./utils/getRelationData'); | ||
var _isConnection2 = _interopRequireDefault(_isConnection); | ||
var _getRelationData2 = _interopRequireDefault(_getRelationData); | ||
var _isManyLink = require('../utils/isManyLink'); | ||
var _getName = require('../utils/getName'); | ||
var _isManyLink2 = _interopRequireDefault(_isManyLink); | ||
var _getName2 = _interopRequireDefault(_getName); | ||
var _StoreError = require('../errors/StoreError'); | ||
var _StoreError2 = _interopRequireDefault(_StoreError); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -34,2 +36,82 @@ | ||
function compareValues(leftValue, operator, rightValue) { | ||
switch (operator) { | ||
case '=': | ||
return leftValue === rightValue; | ||
case '>': | ||
return leftValue > rightValue; | ||
case '>=': | ||
return leftValue >= rightValue; | ||
case '<': | ||
return leftValue < rightValue; | ||
case '<=': | ||
return leftValue <= rightValue; | ||
default: | ||
throw new _StoreError2.default('Unknown operator \'' + operator + '\''); | ||
} | ||
} | ||
function formatData(type, id, entities) { | ||
var shallow = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; | ||
// log warning if entity does not exist | ||
if (!entities.data[type] || !entities.data[type][id]) { | ||
throw new _StoreError2.default('Joined entity not found.', [type, id]); | ||
} | ||
var attributes = {}; | ||
// get full entity | ||
if (!shallow) { | ||
var entity = entities.data[type][id]; | ||
if (entity) { | ||
Object.keys(entity).forEach(function (key) { | ||
if (!(0, _isConnection2.default)(entity[key])) { | ||
attributes[key] = entity[key]; | ||
} | ||
}); | ||
} | ||
} | ||
return _extends({}, attributes, { | ||
__typename: type, | ||
id: id | ||
}); | ||
} | ||
function getRelationData(type, id, name, state, constraints, shallow) { | ||
// log warning if relation does not exist | ||
if (!state.entities.data[type][id][name] || !(0, _isConnection2.default)(state.entities.data[type][id][name])) { | ||
throw new _StoreError2.default('Joined relation "' + name + '" not found.', [type, id]); | ||
} | ||
var childrenTypeIds = state.entities.data[type][id][name].link; | ||
// relation is set to null | ||
if (childrenTypeIds === null) { | ||
return null; | ||
} | ||
// only select shallow link entities | ||
if (shallow) { | ||
if (!(0, _isManyLink2.default)(childrenTypeIds)) { | ||
return formatData(childrenTypeIds[0], childrenTypeIds[1], state.entities, true); | ||
} | ||
return childrenTypeIds.map(function (childrenId) { | ||
return formatData(childrenId[0], childrenId[1], state.entities, true); | ||
}).filter(function (item) { | ||
return item !== undefined; | ||
}); | ||
} | ||
// select full entity | ||
var selector = constraints ? // eslint-disable-next-line no-use-before-define | ||
constraints(new StoreQuery(state, childrenTypeIds)) : // eslint-disable-next-line no-use-before-define | ||
new StoreQuery(state, childrenTypeIds); | ||
return selector.getData(); | ||
} | ||
var StoreQuery = function () { | ||
@@ -42,6 +124,6 @@ function StoreQuery(state, typeIdOrIds) { | ||
this.data = this.isManyLink ? typeIdOrIds.map(function (typeId) { | ||
return (0, _formatData2.default)(typeId[0], typeId[1], state.entities.data); | ||
return formatData(typeId[0], typeId[1], state.entities); | ||
}).filter(function (item) { | ||
return item !== undefined; | ||
}) : (0, _formatData2.default)(typeIdOrIds[0], typeIdOrIds[1], state.entities.data); | ||
}) : formatData(typeIdOrIds[0], typeIdOrIds[1], state.entities); | ||
@@ -58,3 +140,3 @@ this.state = state; | ||
if (!this.isManyLink) { | ||
if (!(0, _compareValues2.default)(this.data[attribute], operator, value)) { | ||
if (!compareValues(this.data[attribute], operator, value)) { | ||
this.data = null; | ||
@@ -65,3 +147,3 @@ } | ||
this.data = this.data.filter(function (data) { | ||
return (0, _compareValues2.default)(data[attribute], operator, value); | ||
return compareValues(data[attribute], operator, value); | ||
}); | ||
@@ -99,5 +181,4 @@ } | ||
var name = (0, _getName2.default)(rawName); | ||
var isStringName = typeof rawName === 'string' || rawName instanceof String; | ||
var resultName = isStringName ? rawName : rawName[0]; | ||
var name = (0, _getKeyName2.default)(rawName); | ||
var resultName = (0, _isString2.default)(rawName) ? rawName : rawName[0]; | ||
@@ -107,3 +188,3 @@ if (this.isManyLink) { | ||
if (_this.data[key]) { | ||
_this.data[key][resultName] = (0, _getRelationData2.default)( | ||
_this.data[key][resultName] = getRelationData( | ||
// eslint-disable-next-line no-underscore-dangle | ||
@@ -114,3 +195,3 @@ _this.data[key].__typename, _this.data[key].id, name, _this.state, constraints, shallow); | ||
} else if (this.data) { | ||
this.data[resultName] = (0, _getRelationData2.default)( | ||
this.data[resultName] = getRelationData( | ||
// eslint-disable-next-line no-underscore-dangle | ||
@@ -117,0 +198,0 @@ this.data.__typename, this.data.id, name, this.state, constraints, shallow); |
@@ -8,5 +8,11 @@ 'use strict'; | ||
function isConnection(value) { | ||
if (!value) { | ||
return false; | ||
} | ||
var hasLinkProperty = Object.prototype.hasOwnProperty.call(value, 'link'); | ||
// A string has also a link property, so we also need to check if value is | ||
// not a function, which it would be in case of a string. | ||
return value !== undefined && value !== null && value.link !== undefined && typeof value.link !== 'function'; | ||
return hasLinkProperty && typeof value.link !== 'function'; | ||
} |
@@ -7,4 +7,11 @@ 'use strict'; | ||
exports.default = isManyLink; | ||
var _isString = require('./isString'); | ||
var _isString2 = _interopRequireDefault(_isString); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function isManyLink(value) { | ||
return !(value === null || typeof value[0] === 'string' || value[0] instanceof String); | ||
return !(value === null || (0, _isString2.default)(value[0])); | ||
} |
@@ -7,4 +7,4 @@ "use strict"; | ||
exports.default = isSameEntity; | ||
function isSameEntity(entity1, entity2) { | ||
return entity1[0] === entity2[0] && entity1[1] === entity2[1]; | ||
function isSameEntity(leftLink, rightLink) { | ||
return leftLink[0] === rightLink[0] && leftLink[1] === rightLink[1]; | ||
} |
{ | ||
"name": "react-transporter", | ||
"version": "0.5.12", | ||
"version": "0.5.13", | ||
"main": "./lib/index.js", | ||
@@ -5,0 +5,0 @@ "description": "React.js Redux GraphQL client", |
Sorry, the diff of this file is not supported yet
104928
2315
50