@prodigyems/graphql-sequelize
Version:
GraphQL & Relay for MySQL & Postgres via Sequelize
248 lines (190 loc) • 10.4 kB
JavaScript
var _bluebird = require('bluebird');
var _bluebird2 = _interopRequireDefault(_bluebird);
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 _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _graphql = require('graphql');
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _argsToFindOptions = require('./argsToFindOptions');
var _argsToFindOptions2 = _interopRequireDefault(_argsToFindOptions);
var _relay = require('./relay');
var _assert = require('assert');
var _assert2 = _interopRequireDefault(_assert);
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); } }
function whereQueryVarsToValues(o, vals) {
[].concat(_toConsumableArray(Object.getOwnPropertyNames(o)), _toConsumableArray(Object.getOwnPropertySymbols(o))).forEach(k => {
if (_lodash2.default.isFunction(o[k])) {
o[k] = o[k](vals);
return;
}
if (_lodash2.default.isObject(o[k])) {
whereQueryVarsToValues(o[k], vals);
}
});
}
function checkIsModel(target) {
return !!target.getTableName;
}
function checkIsAssociation(target) {
return !!target.associationType;
}
function resolverFactory(targetMaybeThunk, models, requiredFilters) {
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
(0, _assert2.default)(typeof targetMaybeThunk === 'function' || checkIsModel(targetMaybeThunk) || checkIsAssociation(targetMaybeThunk), 'resolverFactory should be called with a model, an association or a function (which resolves to a model or an association)');
const contextToOptions = _lodash2.default.assign({}, resolverFactory.contextToOptions, options.contextToOptions);
(0, _assert2.default)(options.include === undefined, 'Include support has been removed in favor of dataloader batching');
if (options.before === undefined) options.before = options => options;
if (options.after === undefined) options.after = result => result;
if (options.handleConnection === undefined) options.handleConnection = true;
return (() => {
var _ref = (0, _bluebird.coroutine)(function* (source, args, context, info) {
let target = typeof targetMaybeThunk === 'function' && !checkIsModel(targetMaybeThunk) ? yield _bluebird2.default.resolve(targetMaybeThunk(source, args, context, info)) : targetMaybeThunk,
isModel = checkIsModel(target),
isAssociation = checkIsAssociation(target),
association = isAssociation && target,
model = isAssociation && target.target || isModel && target,
type = info.returnType,
list = options.list || type instanceof _graphql.GraphQLList || type instanceof _graphql.GraphQLNonNull && type.ofType instanceof _graphql.GraphQLList;
const attributes = Object.entries(model.getAttributes()).filter(function (_ref2) {
var _ref3 = _slicedToArray(_ref2, 2);
let attr = _ref3[1];
return !!attr.filterable;
}).map(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 1);
let key = _ref5[0];
return key;
});
const associations = Object.keys(targetMaybeThunk.associations);
const filterableAttributesFields = {};
const filterableAttributes = [].concat(_toConsumableArray(attributes), _toConsumableArray(Object.entries(models).filter(function (_ref6) {
var _ref7 = _slicedToArray(_ref6, 1);
let key = _ref7[0];
return associations.includes(key) || key === targetMaybeThunk.name;
}).map(function (_ref8) {
var _ref9 = _slicedToArray(_ref8, 2);
let model = _ref9[1];
return Object.entries(model.getAttributes()).filter(function (_ref10) {
var _ref11 = _slicedToArray(_ref10, 2);
let attr = _ref11[1];
return !!attr.filterable;
}).map(function (_ref12) {
var _ref13 = _slicedToArray(_ref12, 2);
let key = _ref13[0],
attr = _ref13[1];
filterableAttributesFields[key] = attr.field;
return key;
});
}).reduce(function (curr, next) {
return [].concat(_toConsumableArray(curr), _toConsumableArray(next));
})));
let targetAttributes = model.options.defaultScope && model.options.defaultScope.attributes || Object.keys(model.getAttributes()),
targetFields = Object.values(model.getAttributes()).filter(function (attr) {
return targetAttributes.includes(attr.fieldName);
}).map(function (attr) {
return attr.field;
}),
findOptions = (0, _argsToFindOptions2.default)(args, filterableAttributes, filterableAttributesFields, [].concat(_toConsumableArray(associations), [targetMaybeThunk.name]), requiredFilters);
info = _extends({}, info, {
type: type,
source: source,
target: target
});
context = context || {};
if ((0, _relay.isConnection)(type)) {
type = (0, _relay.nodeType)(type);
}
type = type.ofType || type;
findOptions.attributes = targetAttributes;
findOptions.logging = findOptions.logging || context.logging;
findOptions.graphqlContext = context;
findOptions.include = associations;
if (args.orderBy && Array.isArray(args.orderBy)) {
findOptions.order = args.orderBy.map(function (order) {
const firstOrder = order.splice(0, 1)[0].split('.');
return [].concat(_toConsumableArray(firstOrder), _toConsumableArray(order)).map(function (field) {
if (!associations.includes(field) && !filterableAttributes.includes(field) && !['ASC', 'DESC'].includes(field)) {
throw new Error(`Unknown order by: ${field}`);
}
return filterableAttributesFields[field] || field;
});
});
}
_lodash2.default.each(contextToOptions, function (as, key) {
findOptions[as] = context[key];
});
return _bluebird2.default.resolve(options.before(findOptions, args, context, info)).then((() => {
var _ref14 = (0, _bluebird.coroutine)(function* (findOptions) {
if (args.where && !_lodash2.default.isEmpty(info.variableValues)) {
whereQueryVarsToValues(args.where, info.variableValues);
whereQueryVarsToValues(findOptions.where, info.variableValues);
}
if (list && !findOptions.order) {
findOptions.order = [[model.primaryKeyAttribute, 'ASC']];
}
if (association) {
if (source[association.as] !== undefined) {
// The user did a manual include
const result = source[association.as];
if (options.handleConnection && (0, _relay.isConnection)(info.returnType)) {
return (0, _relay.handleConnection)(result, args);
}
return result;
} else {
return source[association.accessors.get](findOptions).then(function (result) {
if (options.handleConnection && (0, _relay.isConnection)(info.returnType)) {
return (0, _relay.handleConnection)(result, args);
}
return result;
});
}
}
if (options.operation === 'update') {
const dataArr = Object.entries(args.data).map(function (_ref15) {
var _ref16 = _slicedToArray(_ref15, 2);
let key = _ref16[0],
value = _ref16[1];
return `${key} = ${value}`;
});
if (dataArr.length === 0) {
throw new Error('No data provided to perform an update.');
}
const updateData = dataArr.join(', ');
const joinsArr = Object.entries(targetMaybeThunk.options.associations).map(function (_ref17) {
var _ref18 = _slicedToArray(_ref17, 2);
let key = _ref18[0],
association = _ref18[1];
return `LEFT OUTER JOIN ${models[key].tableName} AS ${key} ON [${key}].[${association.foreignKey}] = [${targetMaybeThunk.name}].[${association.sourceKey}]`;
});
const updateJoins = joinsArr.length === 0 ? '' : joinsArr.join(',');
const whereObj = targetMaybeThunk.sequelize.getQueryInterface().queryGenerator.getWhereConditions(findOptions.where);
const sql = `UPDATE ${targetMaybeThunk.tableName} SET ${updateData} FROM ${targetMaybeThunk.tableName} AS ${targetMaybeThunk.name} ${updateJoins} WHERE ${whereObj}`;
yield targetMaybeThunk.sequelize.query(sql);
}
Object.assign(context, {
count: function count() {
return model.count({
where: findOptions.where,
include: findOptions.include,
distinct: true
});
}
});
findOptions.group = targetFields;
return model[list ? 'findAll' : 'findOne'](findOptions);
});
return function (_x6) {
return _ref14.apply(this, arguments);
};
})()).then(function (result) {
return options.after(result, args, context, info);
});
});
return function (_x2, _x3, _x4, _x5) {
return _ref.apply(this, arguments);
};
})();
}
resolverFactory.contextToOptions = {};
module.exports = resolverFactory;
;