AsyncRedisDocuments 1.0.0.5

dotnet add package AsyncRedisDocuments --version 1.0.0.5                
NuGet\Install-Package AsyncRedisDocuments -Version 1.0.0.5                
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="AsyncRedisDocuments" Version="1.0.0.5" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add AsyncRedisDocuments --version 1.0.0.5                
#r "nuget: AsyncRedisDocuments, 1.0.0.5"                
#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 AsyncRedisDocuments as a Cake Addin
#addin nuget:?package=AsyncRedisDocuments&version=1.0.0.5

// Install AsyncRedisDocuments as a Cake Tool
#tool nuget:?package=AsyncRedisDocuments&version=1.0.0.5                

Available on Nuget

https://www.nuget.org/packages/AsyncRedisDocuments/

Async Redis Documents

Easily create data-driven models using asynchronous programming architecture, easily perform complex queries on your models and use them with ease.

The Basics

IMPORTANT: Requires a Redis database with Search and Query enabled.

The RedisSingleton MUST be initialized.

RedisSingleton.Initialize("host", port, "password");

Begin by implementing an IAsyncDocument

    public class Car : IAsyncDocument
    {
        public string Id { get; set; }

        public string IndexName()
        {
            return "cars";
        }
    }

Next, add an AsyncProperty to your model like so

        public AsyncProperty<string> Description => new(this);

Set the description like so:

await car.Description.SetAsync("my description");

Load it back

var description = await car.Description.GetAsync();

We can even store a complex model into the async property, which is stored as json in redis.

    public class ComplexModel
    {
        public List<List<List<string>>> complexList = new List<List<List<string>>>();
        public string Name { get; set; }
    }
public AsyncProperty<ComplexModel> Model => new(this);

Geerated Indexes & Unique Validation

Indexes are automatically generated by the AsyncDocument system. An index is built where any IAsyncDocument contains a "IndexedProperty" or a "UniqueProperty". Each time you add or remove an IndexedProperty or UniqueProperty your redis index will internally be dropped and recreated to match your new model structure.

Index names are important, make sure you do not give a document an index name used elsewhere. My recommendation is to provide your model an index name similar to the class name.

    public class User : IAsyncDocument
    {
        public string Id { get; set; }

        public UniqueProperty<string> DisplayName => new(this);

        public IndexedProperty<string> Biography => new(this, IndexType.ExactMatch);

        public string IndexName()
        {
            return "users";
        }
    }

The UniqueProperty adds a fast and convienent way to implement unique validation into any application.

  • Important: UniqueProperty automatically handles case insensitivity and does not currently have an option for case sensitivity.
var user = new User
{
    Id = "myUser",
};

var succeeded = await user.DisplayName.SetAsync("TheLegend");

if (succeeded)
{
    Console.WriteLine("Your username was successfully changed.");
}

var username = await user.DisplayName.GetAsync();
Console.WriteLine($"Your new username is: {username}");

The IndexedProperty is very similar, however it does not implement unique validation and so it does not return a boolean for the SetAsync.

Available Index Types include:

Looks for an exact string match. It works on numbers, bools, strings, etc.

IndexType.ExactMatch

Allows numeric searches and operations

IndexType.Numeric

Allows full text search support. Due to redis limitations, your text searches should be alphanumeric.

IndexType.Text
await user.Biography.SetAsync("Example");

var bio = await user.Biography.GetAsync();

Queries

Any model that has an IndexedProperty or a RequiredProperty will be available to be queried.

Find all the results where user bio contains or is similar to "exam"

var results = await QueryExecutor.Query<User>()
.Text(s => s.Biography, "exam")
.SearchAsync();

Find all matches where the text is exactly (with case insensitivity)

var results = await QueryExecutor.Query<User>()
.TextExact(s => s.Biography, "Example")
.SearchAsync();

Return all results where user has money between 0 and 1000, and a username similar or exactly "legend"

var results = await QueryExecutor.Query<User>()
    .Numeric(s => s.Money, 0, 1000)
    .Text(s => s.DisplayName, "legend")
    .Or()
    .TextExact(s => s.Biography, "Example")
    .SearchAsync();

Queries strung together are automatically processed with the AND operation. You have the options of Or and Not for additional complex queries.

var results = await QueryExecutor.Query<User>()
    .Numeric(s => s.Money, 0, 1000)
    .Text(s => s.DisplayName, "legend")
    .Not()
    .TextExact(s => s.Biography, "Example")
    .SearchAsync();

In some cases, you may need to use the query in a non-generic manner

var documentIds = await QueryExecutor.Query()
.TextExact("propertyName", "exactValue")
.SearchAsync("indexName");

You also have the convienent option of "ContainsAsync"

var foundResult = await QueryExecutor.Query()
.TextExact("propertyName", "exactValue")
.ContainsAsync("indexName");

or with generics

var foundResult = await QueryExecutor.Query<User>()
.TextExact(s => s.DisplayName, "legend")
.ContainsAsync();

Document Links serve to directly tie one model to another. Here is an example:

    public class User : IAsyncDocument
    {
        public string Id { get; set; }

        public AsyncLinkSet<Friendship> Friendships => new(this);
        public AsyncManagedLinkSet<Friendship> ManagedFriends => new(this);

        public AsyncLink<User> BestFriend => new(this);
        public ManagedLink<User> ManagedBestFriend => new(this);

        public string IndexName()
        {
            return "users";
        }
    }

    public class Friendship : IAsyncDocument
    {
        public string Id { get;set; }

        public AsyncProperty<DateTime> CreatedDate => new(this);

        public AsyncLink<User> Initiator => new(this);
        public AsyncLink<User> Receiver => new(this);

        public string IndexName()
        {
            return "friends";
        }
    }
var user1 = new User { Id = "user1" };
var user2 = new User { Id = "user2" };

var friendship = new Friendship { Id = Guid.NewGuid().ToString() };
await friendship.Initiator.SetAsync(user1);
await friendship.Receiver.SetAsync(user2);

await user1.Friendships.AddAsync(friendship);
await user2.Friendships.AddAsync(friendship);

var bestFriend = await user1.BestFriend.GetAsync();
await bestFriend.Friendships.GetAsync("id");
  • Important Notes: Unlike standard links, ManagedLinks (e.g., ManagedBestFriend) automatically delete associated documents when the parent document is deleted. For example, if a user is deleted, all their managed links (e.g., their ManagedBestFriend) are also deleted. This setup simplifies handling relationships and ensures data consistency, especially when cascading deletions are necessary.

  • Static Links: Static Links are a permanent connection to another model, that is managed and deleted with the main document.

        public StaticLink<Friendship> Friendship => new(this);

Their purpose is to allow accessing a nested document without actually having to load it from the server, which in some cases gives a level of additional nesting capabilities within a complex application.

await user1.Friendship.Document.CreatedDate.GetAsync();

Collections

Although it is easy to store lists and dictionaries within an AsyncProperty, I have provided more optimized methods of storing potentially large dictionaries and lists.

Store whatever you like, it's really simple.

        public AsyncDictionary<string, CharacterModel> Characters => new(this);
        public AsyncList<string> Friends => new(this);

Most standard methods are available on the dictionary and list components.

bool hasCharacter = await user.Characters.ContainsKeyAsync("characterKey");
var characters = await user.Characters.GetAsync();

var specificCharacter = await user.Characters.GetByKeyAsync("myKey");

Acknowledgements

Authors

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  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 was computed.  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.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on AsyncRedisDocuments:

Package Downloads
BetterRedisIdentity

A better way to use Redis and Identity together.

GitHub repositories

This package is not used by any popular GitHub repositories.