Proxoft.Optional 1.2.0

dotnet add package Proxoft.Optional --version 1.2.0                
NuGet\Install-Package Proxoft.Optional -Version 1.2.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Proxoft.Optional" Version="1.2.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Proxoft.Optional --version 1.2.0                
#r "nuget: Proxoft.Optional, 1.2.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Proxoft.Optional as a Cake Addin
#addin nuget:?package=Proxoft.Optional&version=1.2.0

// Install Proxoft.Optional as a Cake Tool
#tool nuget:?package=Proxoft.Optional&version=1.2.0                

Optional

Optional objects: Option<T>, Either<Left, Right>

Usage


public record Entity(int Id, int Value);


public class Repository
{
    private List<Entity> _entities = new List<Entity>();

    public Option<Entity> FindBy(int id)
    {
        Entity? entity = _entities.SingleOrDefault(e => e.Id == id);
        return entity.WhenNotNull();
    }

    public Either<string, Entity> Create(int value)
    {
        if (value < 0)
        {
            return "cannot create entity with value less then 0";
        }

        int newId = (_entities.LastOrDefault()?.Id ?? 0) + 1;
        Entity newEntity = new(newId, value);
        _entities.Add(newEntity);

        return newEntity;
    }

    public Either<string, Entity> Update(int id, int value)
    {
        if (_entities.All(e => e.Id != id))
        {
            return $"entity with id {id} does not exist";
        }

        if (value < 0)
        {
            return $"cannot update entity {id} with value {value} which is less then 0";
        }

        int index = _entities.FindIndex(e => e.Id == id);
        _entities[index] = _entities[index] with
        {
            Value = value
        };

        return _entities[index];
    }

    public Option<string> Delete(int id)
    {
        if (_entities.All(e => e.Id != id))
        {
            return $"entity with id {id} does not exist";
        }

        _entities.RemoveAll(e => e.Id == id);
        return None.Instance;
    }
}


Console.WriteLine("Let's try options!");

Repository repo = new();

string message = "";

Console.WriteLine();
Console.WriteLine("== Create entity ==");
Console.WriteLine();

message = repo
    .Create(15)
    .Reduce(
        e => $"entity with id {e.Id} created",
        e => e
    );
Console.WriteLine(message);

message = repo
    .Create(-2)
    .Reduce(
        e => $"entity with id {e.Id} created",
        e => e
    );
Console.WriteLine(message);

message = repo
    .Create(9)
    .Reduce(
        e => $"entity with id {e.Id} created",
        e => e
    );
Console.WriteLine(message);

Console.WriteLine();
Console.WriteLine("== Find entity ==");
Console.WriteLine();

Option<Entity> entity = repo
    .FindBy(id: 1);

message = entity
    .Map(e => $"entity {e.Id} has value is {e.Value}")
    .Reduce($"entity with id {1} not found");

Console.WriteLine(message);

Console.WriteLine();
Console.WriteLine("== Find and update entity ==");
Console.WriteLine();

entity = repo
    .FindBy(id: 11);

message = entity
    .Map(e => $"entity {e.Id} has value is {e.Value}")
    .Reduce($"entity with id {11} not found");

Console.WriteLine(message);

message = repo
    .FindBy(id: 1)
    .Either(none: "not found")
    .Map(maybe => TrySetValueAndSave(maybe))
    .Reduce(
        e => $"entity {e.Id} has value is {e.Value}",
        error => error
    );
Console.WriteLine(message);

message = repo
    .FindBy(id: 2)
    .Either(none: "not found")
    .Map(maybe => TrySetValueAndSave(maybe))
    .Reduce(
        e => $"entity {e.Id} has value is {e.Value}",
        error => error
    );
Console.WriteLine(message);

message = repo
    .FindBy(id: 3)
    .Either(none: "3 not found")
    .Map(maybe => TrySetValueAndSave(maybe)) // won't be executed at all
    .Reduce(
        e => $"entities value is {e.Value}",
        error => error
    );
Console.WriteLine(message);

Either<string, Entity> TrySetValueAndSave(Either<string, Entity> entity)
{
    return entity
        .Map(e => e with
        {
            Value = e.Value - 10
        })
        .Map(e => repo.Update(e.Id, e.Value));
}

System.Text.Json serialization

JsonSerializerOptions options = new();
options.Converters.Add(new OptionJsonConverter());
options.Converters.Add(new EitherJsonConverter());

Option<int> maybeNumber = 25;
Option<decima> maybeOtherNumber = None.Instance;

string json1 = JsonSerialize.Serialize(mabeNumber, option);
// returns
// {
//    "option": "some",
//    "value": 25
// }

string json2 = JsonSerialize.Serialize(maybeOtherNumber, option);
// returns
// {
//    "option": "none"
// }

Option<int> desMaybeNumber = JsonSerialize.Deserialize<Option<int>>(json1, option);
// desMaybeNumber is Some<int>(25)

Option<decima> desMaybeOtherNumber = JsonSerialize.Deserialize<Option<int>>(json2, option);
// desMaybeNumber is None


Either<string, int> stringOrInt = 49;
string json3 = JsonSerialize.Serialize(mabeNumber, option);
// returns
// {
//    "either": "right",
//    "value": 49
// }

Either<string, decima> stringOrDecimal = "not a number";
string json4 = JsonSerialize.Serialize(mabeNumber, option);
// returns
// {
//    "either": "left",
//    "value": "not a number"
// }

Either<string, int> desStringOrInt = JsonSerialize.Deserialize<Either<string, int>>(json3, option);
// desStringOrInt == new Right<string, int>(49)

Either<string, decimal> desStringOrDecimal = JsonSerialize.Deserialize<Either<string, int>>(json4, option);
// desStringOrInt == new Left<string, int>("not a number")

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.0 89 7/14/2024
1.1.0 258 12/23/2023
1.0.0 222 11/22/2023