kapix-typegraphql-prisma
Version:

442 lines • 20.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateRelationModel = exports.transformEnums = exports.getMappedOutputTypeName = exports.transformModelWithFields = exports.transformBareModel = exports.transformMappings = exports.transformSchema = void 0;
const tslib_1 = require("tslib");
const types_1 = require("./types");
const helpers_1 = require("./helpers");
const helpers_2 = require("../helpers");
const pluralize_1 = tslib_1.__importDefault(require("pluralize"));
const config_1 = require("../config");
function transformSchema(datamodel, dmmfDocument) {
var _a, _b, _c, _d;
const inputObjectTypes = [
...((_a = datamodel.inputObjectTypes.prisma) !== null && _a !== void 0 ? _a : []),
...((_b = datamodel.inputObjectTypes.model) !== null && _b !== void 0 ? _b : []),
];
const outputObjectTypes = [
...((_c = datamodel.outputObjectTypes.prisma) !== null && _c !== void 0 ? _c : []),
...((_d = datamodel.outputObjectTypes.model) !== null && _d !== void 0 ? _d : []),
];
return {
inputTypes: inputObjectTypes
.filter(uncheckedScalarInputsFilter(dmmfDocument))
.map(transformInputType(dmmfDocument)),
outputTypes: outputObjectTypes.map(transformOutputType(dmmfDocument)),
rootMutationType: datamodel.rootMutationType,
rootQueryType: datamodel.rootQueryType,
};
}
exports.transformSchema = transformSchema;
function transformMappings(mapping, dmmfDocument, options) {
return mapping.map(transformMapping(dmmfDocument, options));
}
exports.transformMappings = transformMappings;
function transformBareModel(model) {
var _a;
const attributeArgs = (0, helpers_1.parseDocumentationAttributes)(model.documentation, "type", "model");
const { output = false } = (0, helpers_1.parseDocumentationAttributes)(model.documentation, "omit", "model");
return {
...model,
typeName: (_a = attributeArgs.name) !== null && _a !== void 0 ? _a : (0, helpers_2.pascalCase)(model.name),
fields: [],
docs: (0, helpers_2.cleanDocsString)(model.documentation),
plural: attributeArgs.plural,
isOmitted: { output },
};
}
exports.transformBareModel = transformBareModel;
function transformModelWithFields(dmmfDocument) {
return (model) => {
return {
...transformBareModel(model),
fields: model.fields.map(transformModelField(dmmfDocument)),
};
};
}
exports.transformModelWithFields = transformModelWithFields;
function transformModelField(dmmfDocument) {
const { omitInputFieldsByDefault, omitOutputFieldsByDefault } = dmmfDocument.options;
return (field) => {
var _a, _b, _c, _d;
const attributeArgs = (0, helpers_1.parseDocumentationAttributes)(field.documentation, "field", "field");
const location = field.kind === "enum"
? "enumTypes"
: field.kind === "object"
? "outputObjectTypes"
: "scalar";
if (typeof field.type !== "string") {
throw new Error(`[Internal Generator Error] Unexpected 'field.type' value: "${field.type}""`);
}
const typeInfo = {
location,
isList: field.isList,
type: dmmfDocument.isModelName(field.type)
? dmmfDocument.getModelTypeName(field.type)
: field.type,
};
const fieldTSType = (0, helpers_2.getFieldTSType)(dmmfDocument, typeInfo, field.isRequired, false);
const typeGraphQLType = (0, helpers_2.getTypeGraphQLType)(typeInfo, dmmfDocument, undefined, undefined, field.isId);
const omitFieldAttribute = (0, helpers_1.parseDocumentationAttributes)(field.documentation, "omit", "field");
return {
...field,
type: field.type,
location,
typeFieldAlias: attributeArgs.name,
fieldTSType,
typeGraphQLType,
docs: (0, helpers_2.cleanDocsString)(field.documentation),
isOmitted: {
input: (_b = (_a = omitFieldAttribute.input) !== null && _a !== void 0 ? _a : omitInputFieldsByDefault === null || omitInputFieldsByDefault === void 0 ? void 0 : omitInputFieldsByDefault.includes(field.name)) !== null && _b !== void 0 ? _b : false,
output: (_d = (_c = omitFieldAttribute.output) !== null && _c !== void 0 ? _c : omitOutputFieldsByDefault === null || omitOutputFieldsByDefault === void 0 ? void 0 : omitOutputFieldsByDefault.includes(field.name)) !== null && _d !== void 0 ? _d : false,
},
};
};
}
function uncheckedScalarInputsFilter(dmmfDocument) {
const { useUncheckedScalarInputs } = dmmfDocument.options;
return (inputType) => {
return useUncheckedScalarInputs
? true
: !inputType.name.includes("Unchecked");
};
}
function transformInputType(dmmfDocument) {
return (inputType) => {
const modelName = (0, helpers_2.getModelNameFromInputType)(inputType.name);
const modelType = modelName
? dmmfDocument.datamodel.models.find(it => it.name === modelName)
: undefined;
return {
...inputType,
typeName: (0, helpers_2.getInputTypeName)(inputType.name, dmmfDocument),
fields: inputType.fields
.filter(field => field.deprecation === undefined)
.map(field => {
var _a;
const modelField = modelType === null || modelType === void 0 ? void 0 : modelType.fields.find(it => it.name === field.name);
const typeName = (_a = modelField === null || modelField === void 0 ? void 0 : modelField.typeFieldAlias) !== null && _a !== void 0 ? _a : field.name;
const selectedInputType = selectInputTypeFromTypes(dmmfDocument)(field.inputTypes);
const typeGraphQLType = (0, helpers_2.getTypeGraphQLType)(selectedInputType, dmmfDocument);
const fieldTSType = (0, helpers_2.getFieldTSType)(dmmfDocument, selectedInputType, field.isRequired, true);
const isOmitted = !(modelField === null || modelField === void 0 ? void 0 : modelField.isOmitted.input)
? false
: typeof modelField.isOmitted.input === "boolean"
? modelField.isOmitted.input
: (modelField.isOmitted.input.includes(config_1.InputOmitSetting.Create) &&
inputType.name.includes("Create")) ||
(modelField.isOmitted.input.includes(config_1.InputOmitSetting.Update) &&
inputType.name.includes("Update")) ||
(modelField.isOmitted.input.includes(config_1.InputOmitSetting.Where) &&
inputType.name.includes("Where")) ||
(modelField.isOmitted.input.includes(config_1.InputOmitSetting.OrderBy) &&
inputType.name.includes("OrderBy"));
return {
...field,
selectedInputType,
typeName,
typeGraphQLType,
fieldTSType,
hasMappedName: field.name !== typeName,
isOmitted,
};
}),
};
};
}
function transformOutputType(dmmfDocument) {
return (outputType) => {
const typeName = getMappedOutputTypeName(dmmfDocument, outputType.name);
return {
...outputType,
typeName,
fields: outputType.fields
.filter(field => field.deprecation === undefined)
.map(field => {
const isFieldRequired = field.isNullable !== true && field.name !== "_count";
const outputTypeInfo = {
...field.outputType,
type: getMappedOutputTypeName(dmmfDocument, field.outputType.type),
};
const fieldTSType = (0, helpers_2.getFieldTSType)(dmmfDocument, outputTypeInfo, isFieldRequired, false);
const typeGraphQLType = (0, helpers_2.getTypeGraphQLType)(outputTypeInfo, dmmfDocument);
const args = field.args.map(arg => {
const selectedInputType = selectInputTypeFromTypes(dmmfDocument)(arg.inputTypes);
const typeGraphQLType = (0, helpers_2.getTypeGraphQLType)(selectedInputType, dmmfDocument);
const fieldTSType = (0, helpers_2.getFieldTSType)(dmmfDocument, selectedInputType, arg.isRequired, true);
return {
...arg,
selectedInputType,
fieldTSType,
typeGraphQLType,
hasMappedName: arg.name !== typeName,
// TODO: add proper mapping in the future if needed
typeName: arg.name,
isOmitted: false,
};
});
const argsTypeName = args.length > 0
? `${typeName}${(0, helpers_2.pascalCase)(field.name)}Args`
: undefined;
return {
...field,
isRequired: isFieldRequired,
outputType: outputTypeInfo,
fieldTSType,
typeGraphQLType,
args,
argsTypeName,
};
}),
};
};
}
function getMappedOutputTypeName(dmmfDocument, outputTypeName) {
if (outputTypeName.startsWith("Aggregate")) {
const modelTypeName = dmmfDocument.getModelTypeName(outputTypeName.replace("Aggregate", ""));
return `Aggregate${modelTypeName}`;
}
if (dmmfDocument.isModelName(outputTypeName)) {
return dmmfDocument.getModelTypeName(outputTypeName);
}
const dedicatedTypeSuffix = [
"CountAggregateOutputType",
"MinAggregateOutputType",
"MaxAggregateOutputType",
"AvgAggregateOutputType",
"SumAggregateOutputType",
"GroupByOutputType",
"CountOutputType",
].find(type => outputTypeName.includes(type));
if (dedicatedTypeSuffix) {
const modelName = outputTypeName.replace(dedicatedTypeSuffix, "");
const operationName = outputTypeName
.replace(modelName, "")
.replace("OutputType", "");
return `${dmmfDocument.getModelTypeName(modelName)}${operationName}`;
}
return outputTypeName;
}
exports.getMappedOutputTypeName = getMappedOutputTypeName;
function transformMapping(dmmfDocument, options) {
return (mapping) => {
var _a;
const { model: modelName, ...availableActions } = mapping;
const modelTypeName = (_a = dmmfDocument.getModelTypeName(modelName)) !== null && _a !== void 0 ? _a : modelName;
const model = dmmfDocument.datamodel.models.find(it => it.name === modelName);
const actions = Object.entries(availableActions)
.sort(([a], [b]) => a.localeCompare(b))
.filter(([actionKind, fieldName]) => {
var _a, _b, _c, _d;
return fieldName &&
getOperationKindName(actionKind, {
mutationActions: (_b = (_a = options.mutationActionsByModel) === null || _a === void 0 ? void 0 : _a[modelName]) !== null && _b !== void 0 ? _b : options.mutationActions,
queryActions: (_d = (_c = options.queryActionsByModel) === null || _c === void 0 ? void 0 : _c[modelName]) !== null && _d !== void 0 ? _d : options.queryActions,
});
}).map(([modelAction, fieldName]) => {
var _a, _b, _c, _d;
const kind = modelAction;
const actionOutputType = dmmfDocument.schema.outputTypes.find(type => type.fields.some(field => field.name === fieldName));
if (!actionOutputType) {
throw new Error(`Cannot find type with field ${fieldName} in root types definitions!`);
}
const method = actionOutputType.fields.find(field => field.name === fieldName);
const argsTypeName = method.args.length > 0
? getMappedArgsTypeName(kind, modelTypeName)
: undefined;
const outputTypeName = method.outputType.type;
const actionResolverName = getMappedActionResolverName(kind, modelTypeName);
const returnTSType = (0, helpers_2.getFieldTSType)(dmmfDocument, method.outputType, method.isRequired, false, mapping.model, modelTypeName);
const typeGraphQLType = (0, helpers_2.getTypeGraphQLType)(method.outputType, dmmfDocument, mapping.model, modelTypeName);
return {
name: getMappedActionName(kind, modelTypeName, model.plural, options),
fieldName,
kind: kind,
operation: getOperationKindName(kind, {
mutationActions: (_b = (_a = options.mutationActionsByModel) === null || _a === void 0 ? void 0 : _a[modelName]) !== null && _b !== void 0 ? _b : options.mutationActions,
queryActions: (_d = (_c = options.queryActionsByModel) === null || _c === void 0 ? void 0 : _c[modelName]) !== null && _d !== void 0 ? _d : options.queryActions,
}),
prismaMethod: getPrismaMethodName(kind),
method,
argsTypeName,
outputTypeName,
actionResolverName,
returnTSType,
typeGraphQLType,
};
});
const resolverName = `${modelTypeName}CrudResolver`;
return {
modelName,
modelTypeName,
actions,
collectionName: (0, helpers_2.camelCase)(mapping.model),
resolverName,
};
};
}
function selectInputTypeFromTypes(dmmfDocument) {
return (inputTypes) => {
const { useUncheckedScalarInputs, useSimpleInputs } = dmmfDocument.options;
let possibleInputTypes;
possibleInputTypes = inputTypes.filter(it => it.location === "inputObjectTypes" &&
// skip inputs with `set` and other fields when simple/flat inputs are enabled
(!useSimpleInputs ||
!(it.type.includes("OperationsInput") || // postgres specific
// mongo specific
it.type.includes("CreateEnvelopeInput") ||
/.+Create.+Input/.test(it.type) ||
/.+Update.+Input/.test(it.type))));
if (possibleInputTypes.length === 0) {
possibleInputTypes = inputTypes.filter(it => it.location === "scalar" && it.type !== "Null");
}
if (possibleInputTypes.length === 0) {
possibleInputTypes = inputTypes.filter(it => it.location === "enumTypes");
}
if (possibleInputTypes.length === 0) {
possibleInputTypes = inputTypes;
}
const selectedInputType = possibleInputTypes.find(it => it.isList) ||
(useUncheckedScalarInputs &&
possibleInputTypes.find(it => it.type.includes("Unchecked"))) ||
possibleInputTypes[0];
let inputType = selectedInputType.type;
if (selectedInputType.location === "enumTypes") {
const enumDef = dmmfDocument.enums.find(it => it.name === inputType);
inputType = enumDef.typeName;
}
else if (selectedInputType.location === "inputObjectTypes") {
inputType = (0, helpers_2.getInputTypeName)(inputType, dmmfDocument);
}
return {
...selectedInputType,
type: inputType,
};
};
}
function getMappedActionName(actionName, typeName, overriddenPlural, options) {
const defaultMappedActionName = mapDefaultActionName(actionName, typeName);
if (options.useOriginalMapping) {
return defaultMappedActionName;
}
const hasNoPlural = !overriddenPlural && typeName === (0, pluralize_1.default)(typeName);
if (hasNoPlural) {
return defaultMappedActionName;
}
switch (actionName) {
case "findUnique": {
return (0, helpers_2.camelCase)(typeName);
}
case "findUniqueOrThrow": {
return `get${typeName}`;
}
case "findMany": {
return (0, helpers_2.camelCase)(overriddenPlural !== null && overriddenPlural !== void 0 ? overriddenPlural : (0, pluralize_1.default)(typeName));
}
default: {
return defaultMappedActionName;
}
}
}
function getMappedArgsTypeName(actionName, typeName) {
return `${(0, helpers_2.pascalCase)(mapDefaultActionName(actionName, typeName))}Args`;
}
function getMappedActionResolverName(actionName, typeName) {
return `${(0, helpers_2.pascalCase)(mapDefaultActionName(actionName, typeName))}Resolver`;
}
function mapDefaultActionName(actionName, typeName) {
return actionName.includes("OrThrow")
? `${actionName.replace("OrThrow", "")}${typeName}OrThrow`
: `${actionName}${typeName}`;
}
function getOperationKindName(actionName, { queryActions, mutationActions, }) {
if ((queryActions !== null && queryActions !== void 0 ? queryActions : config_1.supportedQueryActions).includes(actionName)) {
return "Query";
}
if ((mutationActions !== null && mutationActions !== void 0 ? mutationActions : config_1.supportedMutationActions).includes(actionName)) {
return "Mutation";
}
// throw new Error(`Unsupported operation kind: '${actionName}'`);
}
function getPrismaMethodName(actionKind) {
switch (actionKind) {
case types_1.DMMF.ModelAction.createOne:
return "create";
case types_1.DMMF.ModelAction.updateOne:
return "update";
case types_1.DMMF.ModelAction.upsertOne:
return "upsert";
case types_1.DMMF.ModelAction.deleteOne:
return "delete";
default:
return actionKind;
}
}
const ENUM_SUFFIXES = ["OrderByRelevanceFieldEnum", "ScalarFieldEnum"];
function transformEnums(dmmfDocument) {
return (enumDef) => {
let modelName = undefined;
let typeName = enumDef.name;
const detectedSuffix = ENUM_SUFFIXES.find(suffix => enumDef.name.endsWith(suffix));
if (detectedSuffix) {
modelName = enumDef.name.replace(detectedSuffix, "");
typeName = `${dmmfDocument.getModelTypeName(modelName)}${detectedSuffix}`;
}
const enumValues = enumDef.values;
const valuesMap = enumValues.map(enumValue => {
const isString = typeof enumValue === "string";
const enumValueName = isString ? enumValue : enumValue.name;
const enumDbValue = isString
? enumValueName
: enumValue.dbName || enumValueName;
return {
value: enumDbValue,
name: (modelName &&
dmmfDocument.getModelFieldAlias(modelName, enumValueName)) ||
enumValueName,
};
});
const model = {
values: valuesMap.map(v => v.value),
};
return {
...enumDef,
...model,
docs: "documentation" in enumDef
? (0, helpers_2.cleanDocsString)(enumDef.documentation)
: undefined,
typeName,
valuesMap,
};
};
}
exports.transformEnums = transformEnums;
function generateRelationModel(dmmfDocument) {
return (model) => {
const outputType = dmmfDocument.schema.outputTypes.find(type => type.name === model.name);
const resolverName = `${model.typeName}RelationsResolver`;
const relationFields = model.fields
.filter(field => field.relationName &&
!field.isOmitted.output &&
outputType.fields.some(it => it.name === field.name))
.map(field => {
const outputTypeField = outputType.fields.find(it => it.name === field.name);
const argsTypeName = outputTypeField.args.length > 0
? `${model.typeName}${(0, helpers_2.pascalCase)(field.name)}Args`
: undefined;
return {
...field,
outputTypeField,
argsTypeName,
type: dmmfDocument.getModelTypeName(field.type),
};
});
return {
model,
outputType,
relationFields,
resolverName,
};
};
}
exports.generateRelationModel = generateRelationModel;
//# sourceMappingURL=transform.js.map