UNPKG

@pothos/core

Version:

Pothos (formerly GiraphQL) is a plugin based schema builder for creating code-first GraphQL schemas in typescript

139 lines (138 loc) 5.42 kB
import { PothosSchemaError } from '../errors.js'; import { unwrapInputFieldType } from './params.js'; export function resolveInputTypeConfig(type, buildCache) { if (type.kind === "List") { return resolveInputTypeConfig(type.type, buildCache); } const config = buildCache.getTypeConfig(type.ref); if (config.kind === "Enum" || config.kind === "Scalar" || config.kind === "InputObject") { return config; } throw new PothosSchemaError(`Unexpected config type ${config.kind} for input ref ${String(type.ref)}`); } export function mapInputFields(inputs, buildCache, mapper, cache = new Map()) { const filterMappings = new Map(); const hasMappings = new Map(); return filterMapped(internalMapInputFields(inputs, buildCache, mapper, cache)); function filterMapped(map) { if (filterMappings.has(map)) { return filterMappings.get(map); } const filtered = new Map(); filterMappings.set(map, filtered); map.forEach((mapping, fieldName) => { if (mapping.kind === "Enum" || mapping.kind === "Scalar") { filtered.set(fieldName, mapping); return; } const hasNestedMappings = mapping.fields.map ? checkForMappings(mapping.fields.map, hasMappings) : false; if (mapping.value !== null || hasNestedMappings) { const filteredTypeFields = mapping.fields.map ? filterMapped(mapping.fields.map) : null; const mappingForType = { ...mapping, fields: { configs: mapping.fields.configs, map: filteredTypeFields } }; filtered.set(fieldName, mappingForType); } }); return filtered.size > 0 ? filtered : null; } function checkForMappings(map, hasMappings) { if (hasMappings.has(map)) { return hasMappings.get(map); } hasMappings.set(map, false); let result = false; for (const mapping of map.values()) { if (mapping.value !== null) { result = true; } else if (mapping.kind === "InputObject" && mapping.fields.map && checkForMappings(mapping.fields.map, hasMappings)) { result = true; } } hasMappings.set(map, result); return result; } } function internalMapInputFields(inputs, buildCache, mapper, seenTypes) { const map = new Map(); for (const [fieldName, inputField] of Object.entries(inputs)) { const typeConfig = resolveInputTypeConfig(inputField.type, buildCache); const fieldMapping = mapper(inputField); if (typeConfig.kind === "Enum" || typeConfig.kind === "Scalar") { if (fieldMapping !== null) { map.set(fieldName, { kind: typeConfig.kind, isList: inputField.type.kind === "List", listDepth: getListDepth(inputField.type), config: inputField, value: fieldMapping }); } continue; } const inputFieldConfigs = buildCache.getInputTypeFieldConfigs(unwrapInputFieldType(inputField.type)); if (!seenTypes.has(typeConfig.name)) { const typeEntry = { configs: inputFieldConfigs, map: new Map() }; seenTypes.set(typeConfig.name, typeEntry); typeEntry.map = internalMapInputFields(inputFieldConfigs, buildCache, mapper, seenTypes); } const typeFields = seenTypes.get(typeConfig.name); map.set(fieldName, { kind: typeConfig.kind, isList: inputField.type.kind === "List", listDepth: getListDepth(inputField.type), config: inputField, value: fieldMapping, fields: typeFields }); } return map; } export function createInputValueMapper(argMap, mapValue) { return function mapObject(obj, map = argMap, ...args) { const mapped = { ...obj }; map.forEach((field, fieldName) => { let fieldVal = obj[fieldName]; if (fieldVal === null || fieldVal === undefined) { return; } if (field.kind === "InputObject" && field.fields.map) { fieldVal = mapListValue(fieldVal, field.listDepth, (val) => val && mapObject(val, field.fields.map, ...args)); mapped[fieldName] = fieldVal; } if (field.kind !== "InputObject" || field.value !== null) { mapped[fieldName] = mapListValue(fieldVal, field.listDepth, (val) => val == null ? val : mapValue(val, field, ...args)); } }); return mapped; }; } function getListDepth(type) { let depth = 0; let current = type; while (current.kind === "List") { depth++; current = current.type; } return depth; } function mapListValue(value, listDepth, mapper) { if (listDepth === 0) { return mapper(value); } if (!Array.isArray(value)) { return value; } return value.map((item) => listDepth > 1 ? mapListValue(item, listDepth - 1, mapper) : mapper(item)); } //# sourceMappingURL=input.js.map