shyft
Version:
Model driven GraphQL API framework
336 lines (335 loc) • 17.3 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateGraphQLSchema = exports.registerActions = exports.extendModelsForGql = exports.getTypeForEntityFromGraphRegistry = void 0;
var graphql_1 = require("graphql");
var graphql_relay_1 = require("graphql-relay");
var json_shaper_1 = require("json-shaper");
var Action_1 = require("../engine/action/Action");
var Configuration_1 = require("../engine/configuration/Configuration");
var dataTypes_1 = require("../engine/datatype/dataTypes");
var Entity_1 = require("../engine/entity/Entity");
var ShadowEntity_1 = require("../engine/entity/ShadowEntity");
var ViewEntity_1 = require("../engine/entity/ViewEntity");
var action_1 = require("./action");
var connection_1 = require("./connection");
var graphRegistry_1 = require("./graphRegistry");
var mutation_1 = require("./mutation");
var operation_1 = require("./operation");
var ProtocolGraphQL_1 = require("./ProtocolGraphQL");
var protocolGraphqlConstants_1 = require("./protocolGraphqlConstants");
var query_1 = require("./query");
var registry_1 = require("./registry");
var resolver_1 = require("./resolver");
var subscription_1 = require("./subscription");
var getTypeForEntityFromGraphRegistry = function (entity) {
var typeName = registry_1.getRegisteredEntity(entity.name).typeName;
return graphRegistry_1.graphRegistry.types[typeName];
};
exports.getTypeForEntityFromGraphRegistry = getTypeForEntityFromGraphRegistry;
// prepare models for graphql
var extendModelsForGql = function (entities) {
var protocolConfiguration = ProtocolGraphQL_1.ProtocolGraphQL.getProtocolConfiguration();
var _loop_1 = function (entity) {
var dataShaperMap = {};
var reverseDataShaperMap = {};
var attributes = {};
for (var _b = 0, _c = Object.values(entity.getAttributes()); _b < _c.length; _b++) {
var attribute = _c[_b];
var fieldName = attribute.primary
? 'id'
: protocolConfiguration.generateFieldName(attribute);
// TODO: name does not exist on AttributeBase
// eslint-disable-next-line dot-notation
dataShaperMap[fieldName] = attribute['name'];
// TODO: name does not exist on AttributeBase
// eslint-disable-next-line dot-notation
reverseDataShaperMap[attribute['name']] = fieldName;
var fieldNameI18n = void 0;
var fieldNameI18nJson = void 0;
if (attribute.i18n) {
fieldNameI18n = protocolConfiguration.generateI18nFieldName(attribute);
// TODO: name does not exist on AttributeBase
// eslint-disable-next-line dot-notation
dataShaperMap[fieldNameI18n] = attribute['name'] + ".i18n";
// TODO: name does not exist on AttributeBase
// eslint-disable-next-line dot-notation
reverseDataShaperMap[attribute['name'] + ".i18n"] = fieldNameI18n;
fieldNameI18nJson =
protocolConfiguration.generateI18nJsonFieldName(attribute);
// TODO: name does not exist on AttributeBase
// eslint-disable-next-line dot-notation
dataShaperMap[fieldNameI18nJson] = attribute['name'] + ".i18n";
// no i18n JSON output mapping for reverse shaper map
// so it doesn't overwrite values in mutation inputs
}
// TODO: name does not exist on AttributeBase
// eslint-disable-next-line dot-notation
attributes[attribute['name']] = {
fieldName: fieldName,
fieldNameI18n: fieldNameI18n,
fieldNameI18nJson: fieldNameI18nJson,
};
}
// forward relay type promoter field as well
dataShaperMap[protocolGraphqlConstants_1.RELAY_TYPE_PROMOTER_FIELD] = protocolGraphqlConstants_1.RELAY_TYPE_PROMOTER_FIELD;
reverseDataShaperMap[protocolGraphqlConstants_1.RELAY_TYPE_PROMOTER_FIELD] = protocolGraphqlConstants_1.RELAY_TYPE_PROMOTER_FIELD;
// generate json shaper - translate schema attribute names to graphql attribute names
var dataShaper = json_shaper_1.shaper(dataShaperMap);
var reverseDataShaper = json_shaper_1.shaper(reverseDataShaperMap);
registry_1.registerEntity({
entity: entity,
typeName: protocolConfiguration.generateEntityTypeName(entity),
typeNamePlural: protocolConfiguration.generateEntityTypeNamePlural(entity),
typeNamePascalCase: protocolConfiguration.generateEntityTypeNamePascalCase(entity),
typeNamePluralPascalCase: protocolConfiguration.generateEntityTypeNamePluralPascalCase(entity),
attributes: attributes,
dataShaper: function (data) {
return data ? dataShaper(data) : data;
},
dataSetShaper: function (set) {
return set.map(dataShaper);
},
reverseDataShaper: function (data) {
return data ? reverseDataShaper(data) : data;
},
});
};
for (var _i = 0, _a = Object.values(entities); _i < _a.length; _i++) {
var entity = _a[_i];
_loop_1(entity);
}
};
exports.extendModelsForGql = extendModelsForGql;
// get node definitions for relay
var getNodeDefinitions = function () {
var idFetcher = function (globalId, context) {
var _a = graphql_relay_1.fromGlobalId(globalId), type = _a.type, id = _a.id;
// resolve based on type and id
var entity = graphRegistry_1.graphRegistry.types[type]
? graphRegistry_1.graphRegistry.types[type].entity
: null;
if (entity) {
var resolver = resolver_1.resolveByFindOne(entity, function () { return id; });
return resolver(null, null, context);
}
return null;
};
var typeResolver = function (obj) {
var typeName = obj[protocolGraphqlConstants_1.RELAY_TYPE_PROMOTER_FIELD];
return graphRegistry_1.graphRegistry.types[typeName]
? graphRegistry_1.graphRegistry.types[typeName].type
: null;
};
return __assign(__assign({}, graphql_relay_1.nodeDefinitions(idFetcher, typeResolver)), { idFetcher: idFetcher });
};
var registerAction = function (action) {
var actionName = action.name;
graphRegistry_1.graphRegistry.actions[actionName] = {
action: action,
};
};
var registerActions = function (actions) {
for (var _i = 0, _a = Object.values(actions); _i < _a.length; _i++) {
var action = _a[_i];
registerAction(action);
}
};
exports.registerActions = registerActions;
var generateGraphQLSchema = function (configuration) {
if (!Configuration_1.isConfiguration(configuration)) {
throw new Error('Invalid configuration object provided to generateGraphQLSchema()');
}
var schema = configuration.getSchema();
var protocolConfiguration = configuration.getProtocolConfiguration();
ProtocolGraphQL_1.ProtocolGraphQL.setProtocolConfiguration(protocolConfiguration);
var _a = getNodeDefinitions(), nodeInterface = _a.nodeInterface, nodeField = _a.nodeField, idFetcher = _a.idFetcher;
exports.registerActions(schema.getActions());
// prepare models for graphql
exports.extendModelsForGql(schema.getEntities());
var _loop_2 = function (entity) {
var typeName = registry_1.getRegisteredEntity(entity.name).typeName;
var objectType = new graphql_1.GraphQLObjectType({
name: protocolConfiguration.generateEntityTypeNamePascalCase(entity),
description: entity.description,
interfaces: [nodeInterface],
fields: function () {
var fields = {
id: {
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID),
},
nodeId: {
description: 'The node ID of an object',
type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLID),
resolve: function (obj) { return graphql_relay_1.toGlobalId(typeName, obj.id); },
},
};
var fieldsReference = {};
var fieldsI18n = {};
var _loop_3 = function (attribute) {
if (attribute.hidden || attribute.mutationInput) {
return "continue";
}
var _b = registry_1.getRegisteredEntityAttribute(entity.name, attribute['name']), gqlFieldName = _b.fieldName, gqlFieldNameI18nJson = _b.fieldNameI18nJson;
// const field = {
// description: attribute.description,
// };
var attributeType = attribute.type;
// it's a reference
if (Entity_1.isEntity(attributeType) || ShadowEntity_1.isShadowEntity(attributeType)) {
var targetEntity = attributeType;
var primaryAttribute = targetEntity.getPrimaryAttribute();
attributeType = primaryAttribute.type;
// const reference = {
// description: attribute.description,
// };
var targetTypeName = registry_1.getRegisteredEntity(targetEntity.name).typeName;
// reference.type = graphRegistry.types[targetTypeName].type;
// reference.resolve = resolveByFindOne(
// targetEntity,
// ({ source }) => source[gqlFieldName],
// );
var reference = {
description: attribute.description,
type: graphRegistry_1.graphRegistry.types[targetTypeName].type,
resolve: resolver_1.resolveByFindOne(targetEntity, function (_a) {
var source = _a.source;
return source[gqlFieldName];
}),
};
var referenceFieldName = protocolConfiguration.generateReferenceFieldName(targetEntity, attribute);
fieldsReference[referenceFieldName] = reference;
}
var fieldType = ProtocolGraphQL_1.ProtocolGraphQL.convertToProtocolDataType(attributeType, entity.name, false);
// make it non-nullable if it's required
// if (attribute.required) {
// field.type = new GraphQLNonNull(fieldType);
// } else {
// field.type = fieldType;
// }
// use computed value's function as the field resolver
// if (attribute.resolve) {
// field.resolve = attribute.resolve;
// }
var field = {
description: attribute.description,
type: attribute.required
? new graphql_1.GraphQLNonNull(fieldType)
: fieldType,
resolve: attribute.resolve
? function (obj, args, context, info) { return attribute.resolve({ obj: obj, args: args, context: context, info: info }); }
: undefined,
};
fields[gqlFieldName] = field;
if (attribute.i18n) {
// JSON i18n output
var i18nJsonFieldType = ProtocolGraphQL_1.ProtocolGraphQL.convertToProtocolDataType(dataTypes_1.DataTypeI18n, entity.name, false);
var i18nJsonField = {
type: attribute.required
? new graphql_1.GraphQLNonNull(i18nJsonFieldType)
: i18nJsonFieldType,
description: "Translations of **`" + gqlFieldName + "`** in JSON format",
};
fieldsI18n[gqlFieldNameI18nJson] = i18nJsonField;
// Object Type i18n output
var i18nFieldType = new graphql_1.GraphQLObjectType({
name: protocolConfiguration.generateI18nFieldTypeName(entity, attribute),
description: "Translations of **`" + gqlFieldName + "`**",
fields: function () {
var languages = configuration.getLanguages();
var i18nFields = {};
languages.map(function (language, langIdx) {
var type = langIdx === 0 && attribute.required
? new graphql_1.GraphQLNonNull(fieldType)
: fieldType;
i18nFields[language] = {
type: type,
};
});
return i18nFields;
},
});
var gqlFieldNameI18n = registry_1.getRegisteredEntityAttribute(entity.name, attribute['name']).fieldNameI18n;
fieldsI18n[gqlFieldNameI18n] = {
type: attribute.required
? new graphql_1.GraphQLNonNull(i18nFieldType)
: i18nFieldType,
};
}
};
for (var _i = 0, _a = Object.values(entity.getAttributes()); _i < _a.length; _i++) {
var attribute = _a[_i];
_loop_3(attribute);
}
Object.assign(fields, fieldsI18n, fieldsReference, Entity_1.isEntity(entity)
? connection_1.generateReverseConnections(configuration, graphRegistry_1.graphRegistry, entity)
: {});
return fields;
},
});
graphRegistry_1.graphRegistry.types[typeName] = {
entity: entity,
type: objectType,
};
if (Entity_1.isEntity(entity) || ViewEntity_1.isViewEntity(entity)) {
connection_1.registerConnection(graphRegistry_1.graphRegistry, entity);
}
};
for (var _i = 0, _b = Object.values(schema.getEntities()); _i < _b.length; _i++) {
var entity = _b[_i];
_loop_2(entity);
}
operation_1.generateInstanceUniquenessInputs(graphRegistry_1.graphRegistry);
// build the query type
var queryType = new graphql_1.GraphQLObjectType({
name: 'Query',
// root: 'The root query type',
fields: function () {
var listQueries = query_1.generateListQueries(graphRegistry_1.graphRegistry);
var instanceQueries = query_1.generateInstanceQueries(graphRegistry_1.graphRegistry, idFetcher);
var actions = action_1.generateActions(graphRegistry_1.graphRegistry, Action_1.ACTION_TYPE_QUERY);
// override args.id of relay to args.nodeId
nodeField.args.nodeId = nodeField.args.id;
nodeField.resolve = function (_obj, _a, context, info) {
var nodeId = _a.nodeId;
return idFetcher(nodeId, context, info);
};
delete nodeField.args.id;
return __assign(__assign(__assign({ node: nodeField }, instanceQueries), listQueries), actions);
},
});
var mutationType = new graphql_1.GraphQLObjectType({
name: 'Mutation',
// root: 'The root mutation type',
fields: function () {
var mutations = mutation_1.generateMutations(graphRegistry_1.graphRegistry);
var actions = action_1.generateActions(graphRegistry_1.graphRegistry, Action_1.ACTION_TYPE_MUTATION);
return __assign(__assign({}, mutations), actions);
},
});
var subscriptionType = new graphql_1.GraphQLObjectType({
name: 'Subscription',
// root: 'The root subscription type',
fields: function () {
var subscriptions = subscription_1.generateSubscriptions(graphRegistry_1.graphRegistry);
return subscriptions;
},
});
// put it all together into a graphQL schema
return new graphql_1.GraphQLSchema({
query: queryType,
mutation: mutationType,
subscription: subscriptionType,
});
};
exports.generateGraphQLSchema = generateGraphQLSchema;