simple-graphql
Version:
The simple way to generates GraphQL schemas and Sequelize models from your models definition.
435 lines • 21.6 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const definition_1 = require("../definition");
const graphql_1 = require("graphql");
const relay = __importStar(require("graphql-relay"));
const toGraphQLFieldConfigMap_1 = __importDefault(require("../transformer/toGraphQLFieldConfigMap"));
const globalIdType_1 = __importDefault(require("./type/globalIdType"));
const sequelize_1 = __importDefault(require("sequelize"));
const toGraphQLInputFieldConfigMap_1 = __importDefault(require("../transformer/toGraphQLInputFieldConfigMap"));
const type_1 = __importDefault(require("./type"));
const dataType_1 = __importDefault(require("./dataType"));
const lodash_1 = __importDefault(require("lodash"));
const StringHelper_1 = __importDefault(require("../utils/StringHelper"));
function buildModelType(schema, fieldTypeContext, context) {
var _a;
const typeName = schema.name;
return {
name: typeName,
description: schema.options.description,
inputType: (_a = fieldTypeContext.typeConfig(schema.name + 'Id')) === null || _a === void 0 ? void 0 : _a.inputType,
outputType: new graphql_1.GraphQLObjectType({
name: typeName,
interfaces: [context.interface('Node')],
fields: () => (0, toGraphQLFieldConfigMap_1.default)(typeName, '', Object.assign(Object.assign({ id: {
type: 'Id',
nullable: false,
metadata: {
graphql: {
resolve: function (root) {
return __awaiter(this, void 0, void 0, function* () {
return relay.toGlobalId(schema.name, root.id);
});
}
}
}
} }, schema.config.fields), lodash_1.default.mapValues(schema.config.links, (value, key) => {
var _a;
return Object.assign(Object.assign({}, value.output), { metadata: {
description: value.description || ((_a = value.output.metadata) === null || _a === void 0 ? void 0 : _a.description),
hookOptions: value.hookOptions,
graphql: {
input: value.input,
dependentFields: value.dependentFields,
resolve: value.resolve
}
} });
})), {
hookFieldResolve: (name, options) => context.hookFieldResolve(name, options),
hookQueryResolve: (name, options) => context.hookQueryResolve(name, options),
hookSubscriptionResolve: (name, options) => context.hookSubscriptionResolve(name, options),
hookMutationResolve: (name, options) => context.hookMutationResolve(name, options),
typeConfig: (typeName) => fieldTypeContext.typeConfig(typeName)
})
}),
outputResolve: function (root, args, context, info, sgContext) {
return __awaiter(this, void 0, void 0, function* () {
const fieldName = info.fieldName;
if (root[fieldName]) {
if (typeof root[fieldName] === 'string') {
const { type, id } = StringHelper_1.default.fromGlobalId(root[fieldName]);
if (type === typeName) {
return sgContext.models[typeName].findByPkForGraphQL(id, {}, context, info);
}
else {
return sgContext.models[typeName].findByPkForGraphQL(root[fieldName], {}, context, info);
}
}
else if (typeof root[fieldName] === 'number') {
return sgContext.models[typeName].findByPkForGraphQL(root[fieldName], {}, context, info);
}
else if (typeof root[fieldName].id === 'string') {
const { type, id } = StringHelper_1.default.fromGlobalId(root[fieldName].id);
if (type === typeName) {
return sgContext.models[typeName].findByPkForGraphQL(id, {}, context, info);
}
else {
return root[fieldName];
}
}
else {
return root[fieldName];
}
}
else if (root[fieldName + 'Id']) {
return sgContext.models[typeName].findByPkForGraphQL(root[fieldName + 'Id'], {}, context, info);
}
return null;
});
},
columnOptions: (schema, fieldName, options) => {
var _a, _b, _c, _d, _e, _f, _g, _h;
const foreignField = fieldName;
let onDelete = ((_b = (_a = options.metadata) === null || _a === void 0 ? void 0 : _a.column) === null || _b === void 0 ? void 0 : _b.onDelete) || 'RESTRICT';
let constraints = true;
if (((_d = (_c = options.metadata) === null || _c === void 0 ? void 0 : _c.column) === null || _d === void 0 ? void 0 : _d.constraints) !== undefined) {
constraints = options.metadata.column.constraints;
onDelete = undefined;
}
schema.belongsTo({
[fieldName]: {
target: typeName,
hidden: true,
foreignField: foreignField,
foreignKey: {
name: ((_f = (_e = options.metadata) === null || _e === void 0 ? void 0 : _e.column) === null || _f === void 0 ? void 0 : _f.field) || foreignField + 'Id',
allowNull: options.nullable !== false
},
targetKey: (_h = (_g = options.metadata) === null || _g === void 0 ? void 0 : _g.column) === null || _h === void 0 ? void 0 : _h.targetKey,
onDelete: onDelete,
constraints: constraints
}
});
return null;
}
};
}
function buildModelTypeId(schema, fieldTypeContext) {
const typeName = schema.name + 'Id';
const idType = (0, globalIdType_1.default)(schema.name);
return {
name: typeName,
description: typeName,
inputType: idType,
outputType: idType
};
}
function buildDataType(dataTypeOptions, fieldTypeContext, context) {
var _a, _b;
const toOutputType = (name, options) => {
const outputConfigMap = (0, toGraphQLFieldConfigMap_1.default)(name, '', { '': options }, {
hookFieldResolve: (name, options) => context.hookFieldResolve(name, options),
hookQueryResolve: (name, options) => context.hookQueryResolve(name, options),
hookSubscriptionResolve: (name, options) => context.hookSubscriptionResolve(name, options),
hookMutationResolve: (name, options) => context.hookMutationResolve(name, options),
typeConfig: (typeName) => fieldTypeContext.typeConfig(typeName)
})[''];
return outputConfigMap && outputConfigMap.type;
};
const toInputType = (name, options) => {
const inputConfigMap = (0, toGraphQLInputFieldConfigMap_1.default)(name, { '': options }, fieldTypeContext)[''];
return inputConfigMap && inputConfigMap.type;
};
let outputType, inputType;
outputType = toOutputType(dataTypeOptions.name, dataTypeOptions.definition);
inputType = toInputType(dataTypeOptions.name, dataTypeOptions.definition);
return {
name: dataTypeOptions.name,
description: dataTypeOptions.description || dataTypeOptions.name,
inputType: inputType,
outputType: outputType,
outputResolve: (_b = (_a = dataTypeOptions.definition.metadata) === null || _a === void 0 ? void 0 : _a.graphql) === null || _b === void 0 ? void 0 : _b.resolve,
columnOptions: (schema, fieldName, options) => {
var _a, _b;
let columnOptions = null;
const definition = dataTypeOptions.definition;
if (definition.type) {
const typeConfig = fieldTypeContext.typeConfig(definition.type);
if (!typeConfig) {
throw new Error(`Type "${definition.type}" has not register.`);
}
if (!typeConfig.columnOptions) {
throw new Error(`Column type of "${definition.type}" is not supported.`);
}
columnOptions =
typeof typeConfig.columnOptions === 'function'
? typeConfig.columnOptions(schema, fieldName, options)
: typeConfig.columnOptions;
}
else if (definition.enum) {
columnOptions = {
type: sequelize_1.default.STRING(191)
};
}
else if (definition.elements) {
columnOptions = {
type: sequelize_1.default.JSON
};
}
else {
columnOptions = {
type: sequelize_1.default.JSON
};
}
if (columnOptions) {
columnOptions = Object.assign(Object.assign({}, columnOptions), (dataTypeOptions.columnOptions || {}));
if ((_a = options === null || options === void 0 ? void 0 : options.metadata) === null || _a === void 0 ? void 0 : _a.column) {
columnOptions = Object.assign(Object.assign({}, columnOptions), (_b = options === null || options === void 0 ? void 0 : options.metadata) === null || _b === void 0 ? void 0 : _b.column);
}
return columnOptions;
}
else {
return null;
}
}
};
}
function buildUnionWrapType(wrapType, fieldTypeContext, context) {
const name = `_Union_${wrapType}`;
const typeConfig = fieldTypeContext.typeConfig(wrapType);
if (!(typeConfig === null || typeConfig === void 0 ? void 0 : typeConfig.outputType)) {
throw new Error(`Type ${wrapType} has not register`);
}
return {
name: name,
description: `Union wrap type for ${wrapType}`,
inputType: null,
outputType: new graphql_1.GraphQLObjectType({
name: name,
fields: {
variant: { type: graphql_1.GraphQLString },
value: {
type: typeConfig.outputType,
resolve: (typeConfig === null || typeConfig === void 0 ? void 0 : typeConfig.outputResolve)
? context.hookFieldResolve('value', {
output: { type: wrapType },
resolve: typeConfig.outputResolve
})
: undefined
}
}
}),
columnOptions: { type: sequelize_1.default.JSON }
};
}
function default_1(types, dataTypes, schemas, context) {
const typeMap = {};
const schemaMap = {};
schemas.forEach((schema) => (schemaMap[schema.name] = schema));
const resolves = [
function resolveInterfaceType(typeName) {
if (typeName.endsWith('Interface')) {
const gIntf = context.interface(typeName.substr(0, typeName.length - 'Interface'.length));
if (gIntf) {
return {
name: typeName,
outputType: gIntf
};
}
}
},
function resolveArrayType(typeName) {
if (typeName.startsWith('[') && typeName.endsWith(']')) {
const subTypeName = typeName.substr(1, typeName.length - 2);
const typeConfig = fieldTypeContext.typeConfig(subTypeName);
if (!typeConfig) {
return undefined;
}
return {
name: typeName,
description: `Array of type ${subTypeName}`,
inputType: typeConfig.inputType
? new graphql_1.GraphQLList(typeConfig.inputType)
: null,
outputType: typeConfig.outputType
? new graphql_1.GraphQLList(typeConfig.outputType)
: null,
outputResolve: function (root, args, context, info, sgContext) {
return __awaiter(this, void 0, void 0, function* () {
const fieldName = info.fieldName;
if (schemaMap[subTypeName] != null) {
if (root[fieldName] != null &&
root[fieldName].length > 0 &&
(typeof root[fieldName][0] === 'string' ||
typeof root[fieldName][0] === 'number' ||
(root[fieldName][0] != null &&
typeof root[fieldName][0].id === 'string' &&
StringHelper_1.default.fromGlobalId(root[fieldName][0].id).type ===
subTypeName))) {
const dbModel = sgContext.models[subTypeName];
const ids = root[fieldName].map((r) => {
if (typeof r === 'string' &&
StringHelper_1.default.fromGlobalId(r).type === subTypeName) {
return StringHelper_1.default.fromGlobalId(r).id;
}
else if (r != null &&
typeof r.id === 'string' &&
StringHelper_1.default.fromGlobalId(r.id).type === subTypeName) {
return StringHelper_1.default.fromGlobalId(r.id).id;
}
return r;
});
const option = dbModel.resolveQueryOption({
info: info
});
const list = dbModel.withCache
? yield dbModel.withCache().findAll({
where: { id: { [sequelize_1.default.Op.in]: ids } },
include: option.include,
attributes: option.attributes
})
: yield dbModel.findAll({
where: { id: { [sequelize_1.default.Op.in]: ids } },
include: option.include,
attributes: option.attributes
});
const result = [];
for (const id of ids) {
const element = list.find((e) => '' + e.id === '' + id);
if (element) {
result.push(element);
}
}
return result;
}
}
return root[fieldName];
});
},
columnOptions: { type: sequelize_1.default.JSON }
};
}
},
function resolveModelType(typeName) {
const schema = schemaMap[typeName];
if (schema instanceof definition_1.SGSchema) {
return buildModelType(schema, fieldTypeContext, context);
}
},
function resolveModelIdType(typeName) {
if (typeName.endsWith('Id')) {
const schema = schemaMap[typeName.substring(0, typeName.length - 2)];
if (schema instanceof definition_1.SGSchema) {
return buildModelTypeId(schema, fieldTypeContext);
}
}
},
function resolveModelConnectionType(typeName) {
let schema = typeName.endsWith('Connection')
? schemaMap[typeName.substring(0, typeName.length - 'Connection'.length)]
: null;
if (typeName.endsWith('Edge')) {
schema =
schemaMap[typeName.substring(0, typeName.length - 'Edge'.length)];
}
if (schema) {
const typeConfig = fieldTypeContext.typeConfig(schema.name);
if (!(typeConfig === null || typeConfig === void 0 ? void 0 : typeConfig.outputType)) {
return undefined;
}
const connectionInfo = relay.connectionDefinitions({
name: schema.name,
nodeType: typeConfig.outputType,
connectionFields: {
count: {
type: graphql_1.GraphQLFloat
}
}
});
typeMap[schema.name + 'Connection'] = {
name: schema.name + 'Connection',
description: schema.name + 'Connection',
additionalInput: {
after: { type: 'String' },
first: { type: 'Number' },
before: { type: 'String' },
last: { type: 'Number' }
},
inputType: undefined,
outputType: connectionInfo.connectionType
};
typeMap[schema.name + 'Edge'] = {
name: schema.name + 'Edge',
description: schema.name + 'Edge',
inputType: undefined,
outputType: connectionInfo.edgeType
};
return typeMap[typeName];
}
},
function resolveUnionWrapType(typeName) {
if (typeName.startsWith('_Union_')) {
return buildUnionWrapType(typeName.substr('_Union_'.length), fieldTypeContext, context);
}
}
];
const fieldTypeContext = {
typeConfig: (typeName) => {
if (typeMap[typeName]) {
return typeMap[typeName];
}
for (const resolve of resolves) {
const type = resolve(typeName);
if (type) {
typeMap[type.name] = type;
return type;
}
}
return null;
}
};
for (const f of [...type_1.default, ...types]) {
typeMap[f.name] = f;
}
for (const d of [...dataType_1.default, ...dataTypes]) {
typeMap[d.name] = buildDataType(d, fieldTypeContext, context);
}
return fieldTypeContext;
}
exports.default = default_1;
//# sourceMappingURL=buildFieldTypeContext.js.map