resolverFunctionBodyFromElement function
Implementation
Future<String> resolverFunctionBodyFromElement(
GeneratorCtx ctx,
ExecutableElement element,
) async {
bool _hasValidation(Element? element) =>
element != null && _validateTypeChecker.hasAnnotationOfExact(element);
bool _isValidation(Element? element) =>
element != null && _validationTypeChecker.isAssignableFrom(element);
final validationsInParams = <ParameterElement>[];
final validations = <String>[];
String validationErrorMapAddAll(String validation) {
return 'validationErrorMap.addAll($validation.errorsMap.map((k, v) =>'
' MapEntry(k is Enum ? k.name : k.toString(), v))..removeWhere'
' ((k, v) => v.isEmpty) );';
}
final hasFunctionValidation = _hasValidation(element);
if (hasFunctionValidation) {
final firstIndex = element.name.replaceFirstMapped(
RegExp('[a-zA-Z0-9]'),
(match) => match.input.substring(match.start, match.end).toUpperCase(),
);
final className = '${firstIndex}Args';
final params = [...element.parameters]
..sort((a, b) => _orderForParameter(a) - _orderForParameter(b));
validations.add(
'final _validation = $className(${params.map((e) {
final type = e.type.getDisplayString(withNullability: true);
final getter =
isReqCtx(e.type) ? 'ctx' : '(args["${e.name}"] as $type)';
return '${e.isNamed ? '${e.name}:' : ''}$getter';
}).join(',')}).validate();'
'${validationErrorMapAddAll('_validation')}',
);
}
bool makeGlobalValidation = hasFunctionValidation;
final params = <String>[];
for (final e in element.parameters) {
final argName = e.name;
if (isReqCtx(e.type)) {
const value = 'ctx';
params.add(e.isPositional ? value : '${argName}:$value');
} else {
final type = e.type.getDisplayString(withNullability: true);
final typeName = e.type.getDisplayString(withNullability: false);
final argInfo = argInfoFromElement(e);
final value =
argInfo.inline ? '${argName}Arg' : '(args["${argName}"] as $type)';
if (argInfo.inline) {
// TODO: 2G support generics
validations.add(
'final $value = '
'${ReCase(typeName).camelCase}$serializerSuffix'
'.fromJson(ctx.executionCtx.schema.serdeCtx, args);',
);
}
if (_isValidation(e.type.element)) {
// TODO: 2G pass validation resot in param (don't throw on validation errorĪ)
validationsInParams.add(e);
}
params.add(e.isPositional ? value : '${argName}:$value');
if (!hasFunctionValidation && _hasValidation(e.type.element)) {
makeGlobalValidation = true;
final resultName = '${argName}ValidationResult';
final _addToMap = argInfo.inline
? validationErrorMapAddAll(resultName)
: "validationErrorMap['${argName}'] = [$resultName.toError(property: '${argName}')!];";
validations.add('''
if ($value != null) {
final $resultName = ${typeName}Validation.fromValue($value as $typeName);
if ($resultName.hasErrors) {
$_addToMap
}
}
''');
}
}
}
if (makeGlobalValidation) {
validations.insert(0, '''
final validationErrorMap = <String, List<ValidaError>>{};
''');
validations.add('''
if (validationErrorMap.isNotEmpty) {
throw GraphQLError(
'Input validation error',
extensions: {
'validaErrors': validationErrorMap,
},
sourceError: validationErrorMap,
);
}
''');
}
final _call = '${element.name}(${params.join(',')})';
final classResolver = await getClassResolver(ctx, element);
final handlingFuture =
element is MethodElement && classResolver?.instantiateCode != null;
String _getter = element is MethodElement
? (classResolver?.instantiateCode ?? 'obj.')
: '';
if (handlingFuture) {
final _resolverClassName = element.enclosingElement.name;
_getter = 'final _call = ($_resolverClassName r) => r.$_call;\n'
' final FutureOr<$_resolverClassName> _obj = \n// ignore: unnecessary_non_null_assertion\n$_getter;'
' if (_obj is Future<$_resolverClassName>) return _obj.then(_call);'
' else return _call(_obj);';
}
// if (handlingFuture) {
// _getter = 'return Future.value($_getter).then('
// ' (${element.enclosingElement.name} r) => r.$_call);';
// }
return '''
final args = ctx.args;
${validations.join('\n')}
${handlingFuture ? _getter : 'return $_getter$_call;'}
''';
}