canner
Version:
Build CMS in few lines of code for different data sources
312 lines (282 loc) • 6.81 kB
JavaScript
// @flow
import {pick, update, set, get} from 'lodash';
import {
isCreateArray,
isCreateNestedArrayInArray,
isCreateNestedArrayInObject,
isCreateAndConnect,
isDeleteArray,
isDeleteNestedArrayInArray,
isDeleteNestedArrayInObject,
isDisconnectAndDelete,
isUpdateArray,
isUpdateObject,
isUpdateConnect,
isSwapRootArray,
isSwapArrayInArray,
isSwapArrayInObject,
isConnect,
isDisconnect,
isArrayAction
} from './isAction';
import type {UpdateType, Action, ActionType} from './types';
export function generateAction(arg: {
id: string,
updateType: UpdateType,
value: any,
rootValue: any,
relation: Object,
transformGqlPayload?: Function
}): Action<ActionType> {
if (isCreateArray(arg)) {
const {key} = splitId(arg.id, arg.rootValue);
return {
type: 'CREATE_ARRAY',
payload: {
key,
id: arg.value.id,
value: arg.value
}
}
}
if (isCreateNestedArrayInArray(arg)) {
const {key, id, index, paths} = splitId(arg.id, arg.rootValue);
const item = get(arg.rootValue, [key, index]);
update(item, paths, arr => arr.concat(arg.value));
return {
type: 'UPDATE_ARRAY',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
}
}
if (isCreateNestedArrayInObject(arg)) {
const {key, id, paths} = splitId(arg.id, arg.rootValue);
const item = get(arg.rootValue, [key]);
update(item, paths, arr => arr ? arr.concat(arg.value) : [arg.value]);
return {
type: 'UPDATE_OBJECT',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
}
}
if (isCreateAndConnect(arg)) {
const {key, id, path} = splitId(arg.id, arg.rootValue);
return {
type: 'CREATE_AND_CONNECT',
payload: {
key,
id,
path,
value: arg.value,
relation: arg.relation
}
}
}
if (isDeleteArray(arg)) {
const {key, id} = splitId(arg.id, arg.rootValue);
return {
type: 'DELETE_ARRAY',
payload: {
key,
id,
value: {}
}
}
}
if (isDeleteNestedArrayInArray(arg)) {
const {key, id, index, paths} = splitId(arg.id, arg.rootValue);
const prePaths = paths.slice(0, -1);
const deleteIndex = paths.slice(-1)[0];
const item = get(arg.rootValue, [key, index]);
update(item, prePaths, arr => {
arr.splice(deleteIndex, 1);
return arr;
});
return {
type: 'UPDATE_ARRAY',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
}
}
if (isDeleteNestedArrayInObject(arg)) {
const {key, id, paths} = splitId(arg.id, arg.rootValue);
const prePaths = paths.slice(0, -1);
const deleteIndex = paths.slice(-1)[0];
const item = get(arg.rootValue, [key]);
update(item, prePaths, arr => {
arr.splice(deleteIndex, 1);
return arr;
});
return {
type: 'UPDATE_OBJECT',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
}
}
if (isDisconnectAndDelete(arg)) {
const {key, id, path} = splitId(arg.id, arg.rootValue);
return {
type: 'DISCONNECT_AND_DELETE',
payload: {
key,
id,
path,
value: arg.value,
relation: arg.relation
}
};
}
if (isUpdateArray(arg)) {
const {key, id, paths, index} = splitId(arg.id, arg.rootValue);
const item = get(arg.rootValue, [key, index]);
set(item, paths, arg.value);
return {
type: 'UPDATE_ARRAY',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
};
}
if (isUpdateConnect(arg)) {
/**
* unsupport action
*/
}
if (isUpdateObject(arg)) {
const {key, id, paths} = splitId(arg.id, arg.rootValue);
const item = get(arg.rootValue, key);
set(item, paths, arg.value);
return {
type: 'UPDATE_OBJECT',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
};
}
if (isSwapRootArray(arg)) {
/**
* Swap root array is not allowed,
*/
}
if (isSwapArrayInArray(arg)) {
const {key, id, index, paths} = splitId(arg.id, arg.rootValue);
// $FlowFixMe
const {firstId, secondId} = arg.id;
const nestedArrPath = paths.slice(0, -1);
const item = get(arg.rootValue, [key, index]);
const firstIndex = firstId.split('/').slice(-1)[0];
const secondIndex = secondId.split('/').slice(-1)[0];
update(item, nestedArrPath, arr => {
let newArr = arr.slice();
newArr[firstIndex] = arr[secondIndex];
newArr[secondIndex] = arr[firstIndex];
return newArr;
})
return {
type: 'UPDATE_ARRAY',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
}
}
if (isSwapArrayInObject(arg)) {
const {key, id, paths} = splitId(arg.id, arg.rootValue);
// $FlowFixMe
const {firstId, secondId} = arg.id;
const nestedArrPath = paths.slice(0, -1);
const item = get(arg.rootValue, [key]);
const firstIndex = firstId.split('/').slice(-1)[0];
const secondIndex = secondId.split('/').slice(-1)[0];
update(item, nestedArrPath, arr => {
let newArr = arr.slice();
newArr[firstIndex] = arr[secondIndex];
newArr[secondIndex] = arr[firstIndex];
return newArr;
})
return {
type: 'UPDATE_OBJECT',
payload: {
key,
id,
value: pick(item, paths.slice(0, 1))
}
}
}
if (isConnect(arg)) {
const {key, id, path} = splitId(arg.id, arg.rootValue);
return {
type: 'CONNECT',
payload: {
key,
id,
path,
value: arg.value,
relation: arg.relation,
transformGqlPayload: arg.transformGqlPayload
}
};
}
if (isDisconnect(arg)) {
const {key, id, path} = splitId(arg.id, arg.rootValue);
return {
type: 'DISCONNECT',
payload: {
key,
id,
path,
value: arg.value,
relation: arg.relation
}
};
}
return {
type: 'NOOP',
payload: {
key: '',
value: {}
}
}
}
function splitId(id, rootValue) {
if (typeof id === 'string') {
if (isArrayAction(rootValue, id)) {
const [key, index, ...path] = id.split('/');
const item = rootValue[key][index];
return {
key,
id: item && item.id,
index,
paths: path,
path: path.join('/')
};
} else {
const [key, ...path] = id.split('/');
return {
key,
path: path.join('/'),
paths: path,
id: '',
index: ''
};
}
}
return splitId(id.firstId, rootValue);
}