CSharpFunctionalExtensions icon indicating copy to clipboard operation
CSharpFunctionalExtensions copied to clipboard

Question: return the result

Open FoxTes opened this issue 1 year ago • 1 comments

Hello, colleagues. I can't figure out how to translate this code, namely, it confuses the function in case of failure.

Is it possible to combine it somehow?

Source code

        if (!FullNameRegex.IsValid(message.Text!))
        {
            return await telegramBotClient.SendTextMessageAsync(
                message.Chat.Id, 
                ErrorMessage.ValidationFullName,
                cancellationToken: ct);
        }

        var fullName = await daDataService.ParseFullName(message.Text!);
        if (fullName is null)
        {
            return await telegramBotClient.SendTextMessageAsync(
                message.Chat.Id, 
                ErrorMessage.ValidationFullName, 
                cancellationToken: ct);
        }

        user.Gender = fullName.gender;
        user.Name = fullName.name;
        user.Surname = fullName.surname;
        user.Patronymic = fullName.patronymic;
        user.ActionType = ActionType.Indefinite;
        await userService.UpdateAsync(user, ct);

        return await SendInputWorkoutType(message, ct);

What happened

        var x = await FullNameRegex.IsValidTest(message.Text!)
            .Bind(() => daDataService.ParseFullNameTest(message.Text!));
        if (x.IsFailure)
        {
            return await telegramBotClient.SendTextMessageAsync(
                message.Chat.Id, 
                ErrorMessage.ValidationFullName,
                cancellationToken: ct);
        }
        
        and further...

FoxTes avatar Oct 18 '23 20:10 FoxTes

You can nest an error handler inside Bind, Check, whatever. For your case, more optimal is to have a single "Error case handle" at the end of the chain, I think.

using CSharpFunctionalExtensions;

var user = new User();

await Result.Success(new Message("Bar", "Test Person"))
    .Ensure(message => Result.SuccessIf(DoesTextHaveValidFullName(message.Text), message, Errors.FullNameIsInvalid)
        .TapError(e => new TelegramBotClient().ReplyToMessageAsync(message, "Bot1", e))
    )
    .Bind(message => new SomeDataService().ExtractFullName(message.Text)
        // Translate a service level error to client one, I guess
        .MapError(_ => Errors.FullNameIsInvalid)
        .TapError(e => new TelegramBotClient().ReplyToMessageAsync(message, "Bot2", e))
    )
    .Bind(n => user.UpdatePersonalInfo(n))
    .Tap(u => new UserService().UpdateAsync(u))
    .Tap(() => Console.WriteLine("User personal info has been updated"))
    .TapError(e => Console.WriteLine($"[ERROR] Parse error occurred: {e}"));

bool DoesTextHaveValidFullName(string name) {
    return string.IsNullOrEmpty(name) == false;
}

public record Message(string User, string Text);

public class User {
    public Result<User> UpdatePersonalInfo(string fullName) {
        return this;
    }
}

public static class Errors {
    public const string FullNameIsInvalid = "Invalid Full name";
}

public class SomeDataService {
    public Result<string> ExtractFullName(string message) {
        return Result.SuccessIf(message.Contains("Test Person"), "FullName", "Message does not contain full name");
    } 
}

public class TelegramBotClient {
    public Task ReplyToMessageAsync(Message message, string user, string text) {
        Console.WriteLine($"[{user}] [REPLY TO {message.Text}]: {text}");
        return Task.CompletedTask;
    }
}

public class UserService {
    public Task UpdateAsync(User user) {
        return Task.CompletedTask;
    }
}

PNZeml avatar Nov 24 '23 16:11 PNZeml