canner
Version:
Build CMS in few lines of code for different data sources
328 lines (279 loc) • 8.37 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = actionsToVariables;
exports.removeTypename = removeTypename;
exports.addTypename = addTypename;
exports.parseArrayToSet = parseArrayToSet;
exports.genJsonPath = genJsonPath;
exports.findSchema = findSchema;
exports.addPath = addPath;
exports.genRelationField = genRelationField;
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));
var _lodash = require("lodash");
/**
* change actions to variables which is the argument of graphql mutation
*/
function actionsToVariables(actions, schema) {
var variables = {
payload: {},
where: {}
};
actions.forEach(function (action) {
var _action$payload = action.payload,
_action$payload$path = _action$payload.path,
path = _action$payload$path === void 0 ? '' : _action$payload$path,
value = _action$payload.value,
id = _action$payload.id,
relation = _action$payload.relation,
key = _action$payload.key,
transformGqlPayload = _action$payload.transformGqlPayload;
var relationField = genRelationField(schema, key);
var schemaWithPath = addPath(schema[key], '');
var jsonPath = findSchema(schemaWithPath, function (s) {
return s.type === 'json';
}).map(function (v) {
return v.path;
});
value = parseArrayToSet(value, relationField, jsonPath, path ? "".concat(key, "/").concat(path) : key);
switch (action.type) {
case 'CREATE_ARRAY':
{
// remove null relation
var ensureValue = (0, _lodash.pickBy)(value, function (v, k) {
return v !== null && relationField.indexOf(k) === -1;
});
(0, _lodash.merge)(variables.payload, ensureValue);
break;
}
case 'UPDATE_ARRAY':
case 'UPDATE_OBJECT':
{
(0, _lodash.merge)(variables.payload, value);
(0, _lodash.merge)(variables.where, {
id: id
});
break;
}
case 'CONNECT':
{
if (relation && relation.type === 'toMany') {
(0, _lodash.update)(variables.payload, path.split('/').concat('connect'), function (arr) {
var connectValue = {
id: value.id
};
/* transformGqlPayload is a experimental usage */
if (transformGqlPayload) {
connectValue = transformGqlPayload(connectValue, action);
}
if (!arr || !arr.concat) {
return [connectValue];
}
return arr.concat(connectValue);
});
} else {
(0, _lodash.set)(variables.payload, path.split('/').concat('connect'), {
id: value.id
});
}
if (id) {
(0, _lodash.merge)(variables.where, {
id: id
});
}
break;
}
case 'CREATE_AND_CONNECT':
{
if (relation && relation.type === 'toMany') {
(0, _lodash.update)(variables.payload, path.split('/').concat('create'), function (arr) {
return (arr || []).concat(value);
});
} else {
(0, _lodash.set)(variables.payload, path.split('/').concat('create'), value);
}
(0, _lodash.merge)(variables.where, {
id: id
});
break;
}
case 'DISCONNECT':
if (relation && relation.type === 'toMany') {
(0, _lodash.update)(variables.payload, path.split('/').concat('disconnect'), function (arr) {
return (arr || []).concat({
id: value.id
});
});
} else {
(0, _lodash.set)(variables.payload, path.split('/').concat('disconnect'), true);
}
if (id) {
(0, _lodash.merge)(variables.where, {
id: id
});
}
break;
case 'DISCONNECT_AND_DELETE':
if (relation && relation.type === 'toMany') {
(0, _lodash.update)(variables.payload, path.split('/').concat('delete'), function (arr) {
return (arr || []).concat(value);
});
} else {
(0, _lodash.set)(variables.payload, path.split('/').concat('delete'), true);
}
(0, _lodash.merge)(variables.where, {
id: id
});
break;
case 'DELETE_ARRAY':
(0, _lodash.merge)(variables.where, {
id: id
});
break;
default:
break;
}
});
variables.payload = removeTypename(variables.payload);
if ((0, _lodash.isPlainObject)(variables.payload)) {
delete variables.payload.id;
}
return variables;
}
/**
* add typename: null in every object
*/
function removeTypename(payload) {
if ((0, _lodash.isPlainObject)(payload)) {
var newPayload = (0, _objectSpread2.default)({}, payload);
delete newPayload.__typename;
return (0, _lodash.mapValues)(newPayload, function (value) {
return removeTypename(value);
});
} else if (Array.isArray(payload)) {
return payload.map(function (item) {
return removeTypename(item);
});
}
return payload;
}
function addTypename(payload) {
if ((0, _lodash.isArray)(payload)) {
return payload.map(function (item) {
return addTypename(item);
});
}
if ((0, _lodash.isPlainObject)(payload)) {
return (0, _lodash.mapValues)(payload, function (item, key) {
return key === '__typename' ? item : addTypename(item);
});
} else {
return payload;
}
}
/**
*
* In canner graphql interface,
* an array value should become a object with `set` keyword.
*
* for examples:
* origin payload = {
* hobbies: ['basketball', 'swim']
* name: 'James'
* }
* will become
* {
* hobbies: {
* set: ['basketball', 'swim']
* },
* name: 'James'
* }
*
*/
function parseArrayToSet(payload, relationField, jsonPath, path) {
if (jsonPath.indexOf(path) >= 0) {
return payload;
}
if ((0, _lodash.isArray)(payload) && relationField.indexOf(path) === -1) {
return {
set: payload.map(function (v) {
return parseArrayToSet(v, relationField, jsonPath, path);
})
};
} else if ((0, _lodash.isPlainObject)(payload)) {
return (0, _lodash.mapValues)(payload, function (v, k) {
return parseArrayToSet(v, relationField, jsonPath, path ? "".concat(path, "/").concat(k) : k);
});
} else {
return payload;
}
}
function genJsonPath(schema, key) {
var keySchema = schema[key];
var items = {};
if (keySchema.type === 'object') {
items = keySchema.items;
} else if (keySchema.type === 'array') {
items = keySchema.items.items;
} else {
return [];
}
return Object.keys(items).filter(function (field) {
return items[field].type === 'relation';
});
}
function findSchema(schema, filter) {
var copy = [];
if (filter(schema)) {
copy.push(schema);
}
var items = schema.items;
if (items) {
if (typeof items.type === 'string') {
copy = copy.concat(findSchema(items, filter));
} else {
Object.keys(items).forEach(function (key) {
return copy = copy.concat(findSchema(items[key], filter));
});
}
}
return copy;
}
function addPath(schema, path) {
var items = schema.items,
keyName = schema.keyName;
var schemaPath = path;
if (keyName) {
schemaPath = path ? "".concat(path, "/").concat(keyName) : keyName;
}
schema.path = schemaPath;
if (items) {
if (typeof items.type !== 'string') {
Object.keys(items).forEach(function (key) {
return addPath(schema.items[key], schema.path);
});
} else {
addPath(items, schema.path);
}
}
return schema;
}
/**
* find the relation field in first level relation
*/
function genRelationField(schema, key) {
var keySchema = schema[key];
var items = {};
if (keySchema.type === 'object') {
items = keySchema.items;
} else if (keySchema.type === 'array') {
items = keySchema.items.items;
} else {
return [];
}
return Object.keys(items).filter(function (field) {
return items[field].type === 'relation';
});
}