loopback-graphql
Version:
Add Apollo Server or GraphQL queries on your Loopback server
894 lines (850 loc) • 29.9 kB
JavaScript
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 5);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
module.exports = require("lodash");
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", { value: true });
var _ = __webpack_require__(0);
var PAGINATION = '(where: JSON, after: String, first: Int, before: String, last: Int)';
exports.PAGINATION = PAGINATION;
function base64(i) {
return (new Buffer(i, 'ascii')).toString('base64');
}
function unbase64(i) {
return (new Buffer(i, 'base64')).toString('ascii');
}
var PREFIX = 'connection.';
/**
* Creates the cursor string from an offset.
* @param {String} id the id to convert
* @returns {String} an opaque cursor
*/
function idToCursor(id) {
return base64(PREFIX + id);
}
exports.idToCursor = idToCursor;
/**
* Rederives the offset from the cursor string.
* @param {String} cursor the cursor for conversion
* @returns {String} id converted id
*/
function cursorToId(cursor) {
return unbase64(cursor).substring(PREFIX.length);
}
exports.cursorToId = cursorToId;
function getId(cursor) {
if (cursor === undefined || cursor === null) {
return null;
}
return cursorToId(cursor);
}
exports.getId = getId;
function connectionTypeName(model) {
return model.modelName + "Connection";
}
exports.connectionTypeName = connectionTypeName;
function edgeTypeName(model) {
return model.modelName + "Edge"; // e.g. UserEdge
}
exports.edgeTypeName = edgeTypeName;
function singularModelName(model) {
return model.modelName;
}
exports.singularModelName = singularModelName;
function pluralModelName(model) {
return 'all' + _.upperFirst(model.pluralModelName);
}
exports.pluralModelName = pluralModelName;
function sharedRelations(model) {
return _.pickBy(model.relations, function (rel) { return rel.modelTo && rel.modelTo.shared; });
}
exports.sharedRelations = sharedRelations;
function sharedModels(models) {
return _.filter(models, function (model) {
return model.shared;
});
}
exports.sharedModels = sharedModels;
function methodName(method, model) {
return model.modelName + _.upperFirst(method.name);
}
exports.methodName = methodName;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", { value: true });
var _ = __webpack_require__(0);
var utils_1 = __webpack_require__(1);
function buildSelector(model, args) {
var selector = {
where: args.where || {},
skip: undefined,
limit: undefined,
order: undefined,
};
var begin = utils_1.getId(args.after);
var end = utils_1.getId(args.before);
selector.skip = args.first - args.last || 0;
selector.limit = args.last || args.first;
selector.order = model.getIdName() + (end ? ' DESC' : ' ASC');
if (begin) {
selector.where[model.getIdName()] = selector[model.getIdName()] || {};
selector.where[model.getIdName()].gt = begin;
}
if (end) {
selector.where[model.getIdName()] = selector[model.getIdName()] || {};
selector.where[model.getIdName()].lt = end;
}
return selector;
}
function findOne(model, obj, args, context) {
var id = obj ? obj[model.getIdName()] : args.id;
return model.findById(id);
}
exports.findOne = findOne;
function getCount(model, obj, args, context) {
return model.count(args.where);
}
function getFirst(model, obj, args) {
return model.findOne({
order: model.getIdName() + (args.before ? ' DESC' : ' ASC'),
where: args.where,
})
.then(function (res) {
return res ? res.__data : {};
});
}
function getList(model, obj, args) {
return model.find(buildSelector(model, args));
}
function findAll(model, obj, args, context) {
var response = {
args: args,
count: undefined,
first: undefined,
list: undefined,
};
return getCount(model, obj, args, undefined)
.then(function (count) {
response.count = count;
return getFirst(model, obj, args);
})
.then(function (first) {
response.first = first;
return getList(model, obj, args);
})
.then(function (list) {
response.list = list;
return response;
});
}
exports.findAll = findAll;
function findRelated(rel, obj, args, context) {
if (_.isArray(obj[rel.keyFrom])) {
return [];
}
args.where = (_a = {},
_a[rel.keyTo] = obj[rel.keyFrom],
_a);
return findAll(rel.modelTo, obj, args, context);
var _a;
}
exports.findRelated = findRelated;
function resolveConnection(model) {
return _a = {},
_a[utils_1.connectionTypeName(model)] = (_b = {
totalCount: function (obj, args, context) {
return obj.count;
},
edges: function (obj, args, context) {
return _.map(obj.list, function (node) {
return {
cursor: utils_1.idToCursor(node[model.getIdName()]),
node: node,
};
});
}
},
_b[model.pluralModelName] = function (obj, args, context) {
return obj.list;
},
_b.pageInfo = function (obj, args, context) {
var pageInfo = {
startCursor: null,
endCursor: null,
hasPreviousPage: false,
hasNextPage: false,
};
if (obj.count > 0) {
pageInfo.startCursor = utils_1.idToCursor(obj.list[0][model.getIdName()]);
pageInfo.endCursor = utils_1.idToCursor(obj.list[obj.list.length - 1][model.getIdName()]);
pageInfo.hasNextPage = obj.list.length === obj.args.limit;
pageInfo.hasPreviousPage = obj.list[0][model.getIdName()] !== obj.first[model.getIdName()].toString();
}
return pageInfo;
},
_b),
_a;
var _a, _b;
}
exports.resolveConnection = resolveConnection;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", { value: true });
var graphql_server_express_1 = __webpack_require__(11);
var graphql_tools_1 = __webpack_require__(12);
var bodyParser = __webpack_require__(8);
var ast_1 = __webpack_require__(4);
var resolvers_1 = __webpack_require__(6);
var typedefs_1 = __webpack_require__(7);
function boot(app, options) {
var models = app.models();
var types = ast_1.abstractTypes(models);
var schema = graphql_tools_1.makeExecutableSchema({
typeDefs: typedefs_1.generateTypeDefs(types),
resolvers: resolvers_1.resolvers(models),
resolverValidationOptions: {
requireResolversForAllFields: false,
},
});
var graphiqlPath = options.graphiqlPath || '/graphiql';
var path = options.path || '/graphql';
app.use(path, bodyParser.json(), graphql_server_express_1.graphqlExpress(function (req) {
return {
schema: schema,
context: req,
};
}));
app.use(graphiqlPath, graphql_server_express_1.graphiqlExpress({
endpointURL: path,
}));
}
exports.boot = boot;
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", { value: true });
var _ = __webpack_require__(0);
var utils_1 = __webpack_require__(1);
var execution_1 = __webpack_require__(2);
/*** Loopback Types - GraphQL types
any - JSON
Array - [JSON]
Boolean = boolean
Buffer - not supported
Date - Date (custom scalar)
GeoPoint - not supported
null - not supported
Number = float
Object = JSON (custom scalar)
String - string
***/
var types = {};
var exchangeTypes = {
'any': 'JSON',
'Any': 'JSON',
'Number': 'Int',
'number': 'Int',
'Object': 'JSON',
'object': 'JSON',
};
var SCALARS = {
any: 'JSON',
number: 'Float',
string: 'String',
boolean: 'Boolean',
objectid: 'ID',
date: 'Date',
object: 'JSON',
now: 'Date',
guid: 'ID',
uuid: 'ID',
uuidv4: 'ID',
geopoint: 'GeoPoint',
};
var PAGINATION = 'where: JSON, after: String, first: Int, before: String, last: Int';
var IDPARAMS = 'id: ID!';
function getScalar(type) {
return SCALARS[type.toLowerCase().trim()];
}
function toTypes(union) {
return _.map(union, function (type) {
return getScalar(type) ? getScalar(type) : type;
});
}
function mapProperty(model, property, modelName, propertyName) {
if (property.deprecated) {
return;
}
types[modelName].fields[propertyName] = {
required: property.required,
hidden: model.definition.settings.hidden && model.definition.settings.hidden.indexOf(propertyName) !== -1,
};
var currentProperty = types[modelName].fields[propertyName];
var typeName = modelName + "_" + propertyName;
var propertyType = property.type;
if (propertyType.name === 'Array') {
currentProperty.list = true;
currentProperty.gqlType = 'JSON';
currentProperty.scalar = true;
return;
}
if (_.isArray(property.type)) {
currentProperty.list = true;
propertyType = property.type[0];
}
var scalar = getScalar(propertyType.name);
if (property.defaultFn) {
scalar = getScalar(property.defaultFn);
}
if (scalar) {
currentProperty.scalar = true;
currentProperty.gqlType = scalar;
if (property.enum) {
types[typeName] = {
values: property.enum,
category: 'ENUM',
};
currentProperty.gqlType = typeName;
}
}
if (propertyType.name === 'ModelConstructor' && property.defaultFn !== 'now') {
currentProperty.gqlType = propertyType.modelName;
var union = propertyType.modelName.split('|');
//type is a union
if (union.length > 1) {
types[typeName] = {
category: 'UNION',
values: toTypes(union),
};
}
else if (propertyType.settings && propertyType.settings.anonymous && propertyType.definition) {
currentProperty.gqlType = typeName;
types[typeName] = {
category: 'TYPE',
input: true,
fields: {},
}; // creating a new type
_.forEach(propertyType.definition.properties, function (p, key) {
mapProperty(propertyType, p, typeName, key);
});
}
}
}
function mapRelation(rel, modelName, relName) {
types[modelName].fields[relName] = {
relation: true,
embed: rel.embed,
gqlType: utils_1.connectionTypeName(rel.modelTo),
args: PAGINATION,
resolver: function (obj, args, context) {
return execution_1.findRelated(rel, obj, args, context);
},
};
}
/*
function generateReturns(name, props) {
if (_.isObject(props)) {
props = [props];
}
let args;
args = _.map(props, prop => {
if (_.isArray(prop.type)) {
return `${prop.arg}: [${toType(prop.type[0])}]${prop.required ? '!' : ''}`;
} else if (toType(prop.type)) {
return `${prop.arg}: ${toType(prop.type)}${prop.required ? '!' : ''}`;
}
return '';
}).join(' \n ');
return args ? `{${args}}` : '';
}
function generateAccepts(name, props) {
let ret = _.map(props, prop => {
let propType = prop.type;
if (_.isArray(prop.type)) {
propType = prop.type[0];
}
return propType ? `${prop.arg}: [${toType(prop.type[0])}]${prop.required ? '!' : ''}` : '';
}).join(' \n ');
return ret ? `(${ret})` : '';
}
*/
function addRemoteHooks(model) {
_.map(model.sharedClass._methods, function (method) {
if (method.accessType !== 'READ' && method.http.path) {
var acceptingParams_1 = '', returnType = 'JSON';
method.accepts.map(function (param) {
var paramType = '';
if (typeof param.type === 'object') {
paramType = 'JSON';
}
else {
if (!SCALARS[param.type.toLowerCase()]) {
paramType = param.type + "Input";
}
else {
paramType = _.upperFirst(param.type);
}
}
if (param.arg) {
acceptingParams_1 += param.arg + ": " + (exchangeTypes[paramType] || paramType) + " ";
}
});
if (method.returns && method.returns[0]) {
if (!SCALARS[method.returns[0].type] && typeof method.returns[0].type !== 'object') {
returnType = "" + method.returns[0].type;
}
else {
returnType = "" + _.upperFirst(method.returns[0].type);
if (typeof method.returns[0].type === 'object') {
returnType = 'JSON';
}
}
}
types.Mutation.fields["" + utils_1.methodName(method, model)] = {
relation: true,
args: acceptingParams_1,
gqlType: "" + (exchangeTypes[returnType] || returnType),
};
}
});
}
function mapRoot(model) {
types.Query.fields[utils_1.singularModelName(model)] = {
relation: true,
args: IDPARAMS,
root: true,
gqlType: utils_1.singularModelName(model),
resolver: function (obj, args, context) {
execution_1.findOne(model, obj, args, context);
},
};
types.Query.fields[utils_1.pluralModelName(model)] = {
relation: true,
root: true,
args: PAGINATION,
gqlType: utils_1.connectionTypeName(model),
resolver: function (obj, args, context) {
execution_1.findAll(model, obj, args, context);
},
};
types.Mutation.fields["save" + utils_1.singularModelName(model)] = {
relation: true,
args: "obj: " + utils_1.singularModelName(model) + "Input!",
gqlType: utils_1.singularModelName(model),
resolver: function (context, args) { return model.upsert(args.obj); },
};
types.Mutation.fields["delete" + utils_1.singularModelName(model)] = {
relation: true,
args: IDPARAMS,
gqlType: " " + utils_1.singularModelName(model),
resolver: function (context, args) {
return model.findById(args.id)
.then(function (instance) { return instance.destroy(); });
},
};
// _.each(model.sharedClass.methods, method => {
// if (method.accessType !== 'READ' && method.http.path) {
// let methodName = methodName(method, model);
// types.Mutation.fields[methodName] = {
// gqlType: `${generateReturns(method.name, method.returns)}`,
// args: `${generateAccepts(method.name, method.accepts)}`
// }
// return `${methodName(method)}
// ${generateAccepts(method.name, method.accepts)}
// : JSON`;
// } else {
// return undefined;
// }
// });
addRemoteHooks(model);
}
function mapConnection(model) {
types[utils_1.connectionTypeName(model)] = {
connection: true,
category: 'TYPE',
fields: (_a = {
pageInfo: {
required: true,
gqlType: 'pageInfo',
},
edges: {
list: true,
gqlType: utils_1.edgeTypeName(model),
resolver: function (obj, args, context) {
return _.map(obj.list, function (node) {
return {
cursor: utils_1.idToCursor(node[model.getIdName()]),
node: node,
};
});
},
},
totalCount: {
gqlType: 'Int',
scalar: true,
resolver: function (obj, args, context) {
return obj.count;
},
}
},
_a[model.pluralModelName] = {
gqlType: utils_1.singularModelName(model),
list: true,
resolver: function (obj, args, context) {
return obj.list;
},
},
_a),
resolver: function (obj, args, context) {
return execution_1.resolveConnection(model);
},
};
types[utils_1.edgeTypeName(model)] = {
category: 'TYPE',
fields: {
node: {
gqlType: utils_1.singularModelName(model),
required: true,
},
cursor: {
gqlType: 'String',
required: true,
},
},
};
var _a;
}
function abstractTypes(models) {
//building all models types & relationships
types.pageInfo = {
category: 'TYPE',
fields: {
hasNextPage: {
gqlType: 'Boolean',
required: true,
},
hasPreviousPage: {
gqlType: 'Boolean',
required: true,
},
startCursor: {
gqlType: 'String',
},
endCursor: {
gqlType: 'String',
},
},
};
types.Query = {
category: 'TYPE',
fields: {},
};
types.Mutation = {
category: 'TYPE',
fields: {},
};
_.forEach(models, function (model) {
if (model.shared) {
mapRoot(model);
}
types[utils_1.singularModelName(model)] = {
category: 'TYPE',
input: true,
fields: {},
};
_.forEach(model.definition.properties, function (property, key) {
mapProperty(model, property, utils_1.singularModelName(model), key);
});
mapConnection(model);
_.forEach(utils_1.sharedRelations(model), function (rel) {
mapRelation(rel, utils_1.singularModelName(model), rel.name);
mapConnection(rel.modelTo);
});
});
return types;
}
exports.abstractTypes = abstractTypes;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", { value: true });
var boot_1 = __webpack_require__(3);
module.exports = boot_1.boot;
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", { value: true });
var _ = __webpack_require__(0);
var utils = __webpack_require__(1);
var execution = __webpack_require__(2);
var GraphQLJSON = __webpack_require__(13);
var GraphQLDate = __webpack_require__(9);
var graphql_geojson_1 = __webpack_require__(10);
var scalarResolvers = {
JSON: GraphQLJSON,
Date: GraphQLDate,
GeoPoint: graphql_geojson_1.CoordinatesScalar,
};
function RelationResolver(model) {
var resolver = {};
_.forEach(utils.sharedRelations(model), function (rel) {
resolver[rel.name] = function (obj, args, context) {
return execution.findRelated(rel, obj, args, context);
};
});
return _a = {},
_a[utils.singularModelName(model)] = resolver,
_a;
var _a;
}
function rootResolver(model) {
return {
Query: (_a = {},
_a["" + utils.pluralModelName(model)] = function (root, args, context) {
return execution.findAll(model, root, args, context);
},
_a["" + utils.singularModelName(model)] = function (obj, args, context) {
return execution.findOne(model, obj, args, context);
},
_a),
Mutation: (_b = {},
_b["save" + utils.singularModelName(model)] = function (context, args) {
return model.upsert(args.obj);
},
_b["delete" + utils.singularModelName(model)] = function (context, args) {
return model.findById(args.id)
.then(function (instance) {
return instance ? instance.destroy() : null;
});
},
_b),
};
var _a, _b;
}
function connectionResolver(model) {
return _a = {},
_a[utils.connectionTypeName(model)] = (_b = {
totalCount: function (obj, args, context) {
return obj.count;
},
edges: function (obj, args, context) {
return _.map(obj.list, function (node) {
return {
cursor: utils.idToCursor(node[model.getIdName()]),
node: node,
};
});
}
},
_b[model.pluralModelName] = function (obj, args, context) {
return obj.list;
},
_b.pageInfo = function (obj, args, context) {
var pageInfo = {
startCursor: null,
endCursor: null,
hasPreviousPage: false,
hasNextPage: false,
};
if (obj.count > 0) {
pageInfo.startCursor = utils.idToCursor(obj.list[0][model.getIdName()]);
pageInfo.endCursor = utils.idToCursor(obj.list[obj.list.length - 1][model.getIdName()]);
pageInfo.hasNextPage = obj.list.length === obj.args.limit;
pageInfo.hasPreviousPage = obj.list[0][model.getIdName()] !== obj.first[model.getIdName()].toString();
}
return pageInfo;
},
_b),
_a;
var _a, _b;
}
function remoteResolver(model) {
var mutation = {};
//model.sharedClass.methods
if (model.sharedClass && model.sharedClass.methods) {
model.sharedClass._methods.map(function (method) {
if (method.accessType !== 'READ' && method.http.path) {
var acceptingParams_1 = [];
method.accepts.map(function (param) {
if (param.arg) {
acceptingParams_1.push(param.arg);
}
});
mutation["" + utils.methodName(method, model)] = function (context, args) {
var params = [];
_.each(method.accepts, function (el, i) {
params[i] = args[el.arg];
});
return model[method.name].apply(model, params);
};
}
});
}
return {
Mutation: mutation,
};
}
/**
* Generate resolvers for all models
*
* @param {Object} models: All loopback Models
* @returns {Object} resolvers functions for all models - queries and mutations
*/
function resolvers(models) {
return _.reduce(models, function (obj, model) {
if (model.shared) {
return _.merge(obj, rootResolver(model), connectionResolver(model), RelationResolver(model), remoteResolver(model));
}
return obj;
}, scalarResolvers);
}
exports.resolvers = resolvers;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
;
Object.defineProperty(exports, "__esModule", { value: true });
var _ = __webpack_require__(0);
var scalarTypes = "\n scalar Date\n scalar JSON\n scalar GeoPoint\n ";
function args(args) {
return args ? "(" + args + ")" : '';
}
function generateInputField(field, name) {
return "\n " + name + " : " + (field.list ? '[' : '') + "\n " + field.gqlType + (field.scalar ? '' : 'Input') + (field.required ? '!' : '') + " " + (field.list ? ']' : '');
}
function generateOutputField(field, name) {
return name + " " + args(field.args) + " : " + (field.list ? '[' : '') + field.gqlType + (field.required ? '!' : '') + " " + (field.list ? ']' : '');
}
function generateTypeDefs(types) {
var categories = {
TYPE: function (type, name) {
var output = _.reduce(type.fields, function (result, field, fieldName) {
return result + generateOutputField(field, fieldName) + ' \n ';
}, '');
var result = "\n type " + name + " {\n " + output + "\n }";
if (type.input) {
var input = _.reduce(type.fields, function (accumulator, field, fieldName) {
return !field.relation ? accumulator + generateInputField(field, fieldName) + ' \n ' : accumulator;
}, '');
result += "input " + name + "Input {\n " + input + "\n }";
}
return result;
},
UNION: function (type, name) {
return "union " + name + " = " + type.values.join(' | ');
},
ENUM: function (type, name) {
return "enum " + name + " {" + type.values.join(' ') + "}";
},
};
return _.reduce(types, function (result, type, name) {
return result + categories[type.category](type, name);
}, scalarTypes);
}
exports.generateTypeDefs = generateTypeDefs;
/***/ }),
/* 8 */
/***/ (function(module, exports) {
module.exports = require("body-parser");
/***/ }),
/* 9 */
/***/ (function(module, exports) {
module.exports = require("graphql-date");
/***/ }),
/* 10 */
/***/ (function(module, exports) {
module.exports = require("graphql-geojson");
/***/ }),
/* 11 */
/***/ (function(module, exports) {
module.exports = require("graphql-server-express");
/***/ }),
/* 12 */
/***/ (function(module, exports) {
module.exports = require("graphql-tools");
/***/ }),
/* 13 */
/***/ (function(module, exports) {
module.exports = require("graphql-type-json");
/***/ })
/******/ ]);
//# sourceMappingURL=index.js_map