Giter VIP home page Giter VIP logo

Comments (3)

yeongjonglim avatar yeongjonglim commented on August 16, 2024

I am also looking at a similar feature like this. On top of that, I am also trying to have Then mixing to aggregate multiple results from previous steps. Maybe the said proposal can also cover the following scenario at the same time, where I frequently will create multiple ErrorOr values that have nothing to do with each other, but will be used in a common function at the end.

var userQuery = await sender.Send(new UserQuery(request.UserExternalId), cancellationToken); --> This method returns ErrorOr value

if (userQuery.IsError)
{
    return userQuery.Errors;
}

return await sender.Send(new TransactionSingleQuery(request.UserExternalId, request.TransactionGroupId), cancellationToken) --> This method returns ErrorOr value
    .ThenAsync(async x =>
    {
        var update = x.TransactionGroup.Update(
            request.TransactionTime,
            request.Description,
            request.Amount,
            userQuery.Value.User, --> This is the part that I hope to be able to chain together in Then mixing from userQuery
            timeProvider.GetUtcNow(),
            from,
            to);

        await repository.UpdateTransactionGroup(update);

        return new TransactionUpdateResult(update.Id);
    })
    .Else(x => x);

from error-or.

ahmtsen avatar ahmtsen commented on August 16, 2024

I am also looking at a similar feature like this. On top of that, I am also trying to have Then mixing to aggregate multiple results from previous steps. Maybe the said proposal can also cover the following scenario at the same time, where I frequently will create multiple ErrorOr values that have nothing to do with each other, but will be used in a common function at the end.

var userQuery = await sender.Send(new UserQuery(request.UserExternalId), cancellationToken); --> This method returns ErrorOr value

if (userQuery.IsError)
{
    return userQuery.Errors;
}

return await sender.Send(new TransactionSingleQuery(request.UserExternalId, request.TransactionGroupId), cancellationToken) --> This method returns ErrorOr value
    .ThenAsync(async x =>
    {
        var update = x.TransactionGroup.Update(
            request.TransactionTime,
            request.Description,
            request.Amount,
            userQuery.Value.User, --> This is the part that I hope to be able to chain together in Then mixing from userQuery
            timeProvider.GetUtcNow(),
            from,
            to);

        await repository.UpdateTransactionGroup(update);

        return new TransactionUpdateResult(update.Id);
    })
    .Else(x => x);

You can achive this behavior by forwarding the result using Tuples.

Created an example for you

using ErrorOr;

ErrorOr<TransactionGroup> Handle(ISender sender, int externalUserId, int transactionGroupId) =>
    new UserQuery(externalUserId)
        .ToErrorOr()
        .Then(userQuery => sender.Send(userQuery))
        .Then(user => (user, new TransactionSingleQuery(externalUserId, transactionGroupId)))
        .Then(tuple => (tuple.Item1, sender.Send(tuple.Item2)))
        .Then(
            (tuple) =>
            {
                User user = tuple.Item1;
                TransactionGroup transactionGroup = tuple.Item2;

                // do work with these

                return transactionGroup;
            }
        );

record User(int Id, string Name);

record UserQuery(int ExternalUserId);

record TransactionSingleQuery(int ExternalUserId, int TransactionGroupId);

record TransactionGroup(int Id, DateTime TransactionDateTime);

interface ISender
{
    User Send(UserQuery query);

    TransactionGroup Send(TransactionSingleQuery query);
}

from error-or.

ahmtsen avatar ahmtsen commented on August 16, 2024

What dou you think about the following propose?

Before:

 public static ErrorOr<SomeResult> Create(string value1, string value2)
 {
     ErrorOr<Value1> value1OrError = Value1.Create(value1);
     ErrorOr<Value2> value2OrError = Value2.Create(value2);
     var errors = new List<Error>();
     errors.AddRange(value1OrError.Errors);
     errors.AddRange(value2OrError.Errors);

    if(errors.Count > 0) {
         return errors;
    }

    return  new SomeResult(value1OrError.Value, value2OrError.Value);
}

After (Option 1 - Separate class)

 public static ErrorOr<SomeResult> Create(string value1, string value2)
 {
     ErrorOr<Value1> value1OrError = Value1.Create(value1);
     ErrorOr<Value2> value2OrError = Value2.Create(value2);

     return ErrorCollector
        .Collect(value1OrError , value2OrError )
        .Then(x => new SomeResult(value1OrError.Value, value2OrError.Value));
 }

After (Option 2 - ErrorOrFactory)

 public static ErrorOr<SomeResult> Create(string value1, string value2)
 {
     ErrorOr<Value1> value1OrError = Value1.Create(value1);
     ErrorOr<Value2> value2OrError = Value2.Create(value2);

     return ErrorOrFactory
        .CollectErrors(value1OrError , value2OrError )
        .Then(() => new SomeResult(value1OrError.Value, value2OrError.Value));
 }

Implementation propose:

 public static ErrorOr<Result> CollectErrors<Result>(params IErrorOr[] errorsToCombine)
 {
     if (errorsToCombine.Any(x => x.IsError))
     {
         return errorsToCombine.SelectMany(x => x.Errors);
     }

     return Result.Success;
 }

Of course, improvements are required to handle cases like null values.

To achieve the similar behavior. I created a custom extension like this.

public static class Errors
{
  public static List<Error> Combine(params IErrorOr[] errorOrs) =>
      errorOrs
          .Where(x => x.IsError)
          .Where(x => x.Errors is not null)
          .SelectMany(x => x.Errors!)
          .ToList();
}

Maybe a static method on Error or ErrorOrFactory will do the trick.

You can find an example usage of the extension method I created below.

ErrorOr<Success> HandleUpdateUser()
{
    User user = GetUser();

    if (
        Errors.Combine(user.SetFirstName(string.Empty), user.SetLastName(string.Empty))
        is var errors
            and { Count: not 0 }
    )
    {
        return errors;
    }

    return Result.Success;
}


class User
{
    public string FirstName { get; private set; }

    public string LastName { get; private set; }

    public ErrorOr<Updated> SetFirstName(string firstName)
    {
        if (string.IsNullOrWhiteSpace(firstName))
        {
            return Error.Validation(description: "First name is required");
        }

        return Result.Updated;
    }

    public ErrorOr<Updated> SetLastName(string lastName)
    {
        if (string.IsNullOrWhiteSpace(lastName))
        {
            return Error.Validation(description: "Last name is required");
        }
        return Result.Updated;
    }
}

from error-or.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.