Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/support transaction #79

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions Examples/CombinationModulesPipeline.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
# Combination modules Pipeline

## An example of pipelines mixing a pipeline with a combination of module commands with JSON & Search

Connect to the Redis server:

```csharp
var redis = ConnectionMultiplexer.Connect("localhost");
```

Setup pipeline connection

```csharp
var db = redis.GetDatabase();
var pipeline = new Pipeline(db);
```

## JSON

Add JsonSet to pipeline

```csharp
pipeline.Json.SetAsync("person:01", "$", new { name = "John", age = 30, city = "New York" });
pipeline.Json.SetAsync("person:02", "$", new { name = "Joy", age = 25, city = "Los Angeles" });
Expand All @@ -23,27 +28,33 @@ pipeline.Json.SetAsync("person:05", "$", new { name = "Michael", age = 55, city
```

## Search

Create the schema to index name as text field, age as a numeric field and city as tag field.

```csharp
var schema = new Schema().AddTextField("name").AddNumericField("age", true).AddTagField("city");
```

Filter the index to only include Jsons with prefix of person:

```csharp
var parameters = FTCreateParams.CreateParams().On(IndexDataType.JSON).Prefix("person:");
```

Create the index via pipeline

```csharp
pipeline.Ft.CreateAsync("person-idx", parameters, schema);
```

Search for all indexed person records
Execute the pipeline

```csharp
var getAllPersons = db.FT().SearchAsync("person-idx", new Query());
pipeline.Execute();
```

Execute the pipeline
Search for all indexed person records

```csharp
pipeline.Execute();
```
var getAllPersons = db.FT().SearchAsync("person-idx", new Query());
```
55 changes: 55 additions & 0 deletions Examples/TransactionsExample.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Transaction

## An example of transactions with Redis modules (JSON.SET, JSON.GET & JSON.NUMINCRBY)

Connect to the Redis server

```cs
var redis = await ConnectionMultiplexer.ConnectAsync("localhost");
var db = redis.GetDatabase();
```

Setup transaction

```cs
var tran = new Transactions(db);
```

Add account details with Json.Set

```cs
tran.Json.SetAsync("accdetails:Jeeva", "$", new { name = "Jeeva", totalAmount= 1000, bankName = "City" });
tran.Json.SetAsync("accdetails:Shachar", "$", new { name = "Shachar", totalAmount = 1000, bankName = "City" });
```

Get the Json response for both Jeeva & Shachar

```cs
var getShachar = tran.Json.GetAsync("accdetails:Shachar");
var getJeeva = tran.Json.GetAsync("accdetails:Jeeva");
```

Debit 200 from Jeeva

```cs
tran.Json.NumIncrbyAsync("accdetails:Jeeva", "$.totalAmount", -200);
```

Credit 200 from Shachar

```cs
tran.Json.NumIncrbyAsync("accdetails:Shachar", "$.totalAmount", 200);
```

Get total amount for both Jeeva = 800 & Shachar = 1200

```cs
var totalAmtOfJeeva = tran.Json.GetAsync("accdetails:Jeeva", path:"$.totalAmount");
var totalAmtOfShachar = tran.Json.GetAsync("accdetails:Shachar", path:"$.totalAmount");
```

Execute the transaction

```cs
var condition = tran.ExecuteAsync();
```
6 changes: 2 additions & 4 deletions src/NRedisStack/Pipeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ public Pipeline(IDatabase db)

private IBatch _batch;

public void Execute()
{
_batch.Execute();
}
public void Execute() => _batch.Execute();


public IBloomCommandsAsync Bf => new BloomCommandsAsync(_batch);
public ICmsCommandsAsync Cms => new CmsCommandsAsync(_batch);
Expand Down
31 changes: 31 additions & 0 deletions src/NRedisStack/Transactions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using StackExchange.Redis;

namespace NRedisStack
{
public class Transactions
{
private ITransaction _transaction;
public IDatabaseAsync Db => _transaction;

public Transactions(IDatabase db)
{
_transaction = db.CreateTransaction();
}

public ConditionResult AddCondition(Condition condition) => _transaction.AddCondition(condition);

public bool Execute(CommandFlags flags = CommandFlags.None) => _transaction.Execute(flags);

public Task<bool> ExecuteAsync(CommandFlags flags = CommandFlags.None) => _transaction.ExecuteAsync(flags);

public IBloomCommandsAsync Bf => new BloomCommandsAsync(_transaction);
public ICmsCommandsAsync Cms => new CmsCommandsAsync(_transaction);
public ICuckooCommandsAsync Cf => new CuckooCommandsAsync(_transaction);
public IGraphCommandsAsync Graph => new GraphCommandsAsync(_transaction);
public IJsonCommandsAsync Json => new JsonCommandsAsync(_transaction);
public ISearchCommandsAsync Ft => new SearchCommandsAsync(_transaction);
public ITdigestCommandsAsync Tdigest => new TdigestCommandsAsync(_transaction);
public ITimeSeriesCommandsAsync Ts => new TimeSeriesCommandsAsync(_transaction);
public ITopKCommandsAsync TopK => new TopKCommandsAsync(_transaction);
}
}
56 changes: 45 additions & 11 deletions tests/NRedisStack.Tests/Examples/ExamplesTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Xunit;
using StackExchange.Redis;
using NRedisStack.RedisStackCommands;
using Moq;
using NRedisStack.Search.FT.CREATE;
using NRedisStack.Search;
using NRedisStack.DataTypes;
using NRedisStack.Literals.Enums;
using NRedisStack.RedisStackCommands;
using NRedisStack.Search;
using NRedisStack.Search.FT.CREATE;
using StackExchange.Redis;
using Xunit;

namespace NRedisStack.Tests;

Expand Down Expand Up @@ -81,8 +81,6 @@ public async Task AsyncExample()
[Fact]
public void PipelineExample()
{
// Connect to the Redis server and Setup 2 Pipelines

// Pipeline can get IDatabase for pipeline
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
Expand All @@ -103,7 +101,7 @@ public void PipelineExample()
// Get the Json response
var getResponse = pipeline.Json.GetAsync("person");

// Execute the pipeline2
// Execute the pipeline
pipeline.Execute();

// Get the result back JSON
Expand Down Expand Up @@ -168,8 +166,8 @@ public async Task PipelineWithAsync()
var db = redis.GetDatabase();
db.Execute("FLUSHALL");
// Setup pipeline connection
var pipeline = new Pipeline(db);

var pipeline = new Pipeline(db);

// Create metedata lables for time-series.
TimeSeriesLabel label1 = new TimeSeriesLabel("temp", "TLV");
Expand Down Expand Up @@ -216,8 +214,44 @@ public async Task PipelineWithAsync()
}

[Fact]
public void TransactionExample()
public async Task TransactionExample()
{
// implementation for transaction
// Connect to the Redis server
var redis = ConnectionMultiplexer.Connect("localhost");

// Get a reference to the database
var db = redis.GetDatabase();
db.Execute("FLUSHALL");

// Setup transaction with IDatabase
var tran = new Transactions(db);

// Add account details with Json.Set to transaction
tran.Json.SetAsync("accdetails:Jeeva", "$", new { name = "Jeeva", totalAmount= 1000, bankName = "City" });
tran.Json.SetAsync("accdetails:Shachar", "$", new { name = "Shachar", totalAmount = 1000, bankName = "City" });

// Get the Json response
var getShachar = tran.Json.GetAsync("accdetails:Shachar");
var getJeeva = tran.Json.GetAsync("accdetails:Jeeva");

// Debit 200 from Jeeva
tran.Json.NumIncrbyAsync("accdetails:Jeeva", "$.totalAmount", -200);

// Credit 200 from Shachar
tran.Json.NumIncrbyAsync("accdetails:Shachar", "$.totalAmount", 200);

// Get total amount for both Jeeva = 800 & Shachar = 1200
var totalAmtOfJeeva = tran.Json.GetAsync("accdetails:Jeeva", path:"$.totalAmount");
var totalAmtOfShachar = tran.Json.GetAsync("accdetails:Shachar", path:"$.totalAmount");

// Execute the transaction
var condition = tran.ExecuteAsync();

// Assert
Assert.True(condition.Result);
Assert.NotEmpty(getJeeva.Result.ToString());
Assert.NotEmpty(getShachar.Result.ToString());
Assert.Equal("[800]", totalAmtOfJeeva.Result.ToString());
Assert.Equal("[1200]", totalAmtOfShachar.Result.ToString());
}
}
89 changes: 89 additions & 0 deletions tests/NRedisStack.Tests/TransactionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Moq;
using NRedisStack.RedisStackCommands;
using NRedisStack.Search;
using NRedisStack.Search.FT.CREATE;
using StackExchange.Redis;
using System.Text.Json;
using Xunit;

namespace NRedisStack.Tests
{
public class TransactionsTests : AbstractNRedisStackTest, IDisposable
{
Mock<IDatabase> _mock = new Mock<IDatabase>();
private readonly string key = "TRX_TESTS";
public TransactionsTests(RedisFixture redisFixture) : base(redisFixture) { }

public void Dispose()
{
redisFixture.Redis.GetDatabase().KeyDelete(key);
}

[Fact]
public async Task TestJsonTransactions()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var transaction = new Transactions(db);
string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 });
var setResponse = transaction.Json.SetAsync(key, "$", jsonPerson);
var getResponse = transaction.Json.GetAsync(key);

transaction.Execute();

Assert.Equal("True", setResponse.Result.ToString());
Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString());
}

[Fact]
public async Task TestModulsTransaction()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
var tran = new Transactions(db);

tran.Bf.ReserveAsync("bf-key", 0.001, 100);
tran.Bf.AddAsync("bf-key", "1");
tran.Cms.InitByDimAsync("cms-key", 100, 5);
tran.Cf.ReserveAsync("cf-key", 100);
tran.Graph.QueryAsync("graph-key", "CREATE ({name:'shachar',age:23})");
tran.Json.SetAsync("json-key", "$", "{}");
tran.Ft.CreateAsync("ft-key", new FTCreateParams(), new Schema().AddTextField("txt"));
tran.Tdigest.CreateAsync("tdigest-key", 100);
tran.Ts.CreateAsync("ts-key", 100);
tran.TopK.ReserveAsync("topk-key", 100, 100, 100);

Assert.False(db.KeyExists("bf-key"));
Assert.False(db.KeyExists("cms-key"));
Assert.False(db.KeyExists("cf-key"));
Assert.False(db.KeyExists("graph-key"));
Assert.False(db.KeyExists("json-key"));
Assert.Equal(0, db.FT()._List().Length);
Assert.False(db.KeyExists("tdigest-key"));
Assert.False(db.KeyExists("ts-key"));
Assert.False(db.KeyExists("topk-key"));

tran.Execute();

Assert.True(db.KeyExists("bf-key"));
Assert.True(db.KeyExists("cms-key"));
Assert.True(db.KeyExists("cf-key"));
Assert.True(db.KeyExists("graph-key"));
Assert.True(db.KeyExists("json-key"));
Assert.True(db.FT()._List().Length == 1);
Assert.True(db.KeyExists("tdigest-key"));
Assert.True(db.KeyExists("ts-key"));
Assert.True(db.KeyExists("topk-key"));

Assert.True(db.BF().Exists("bf-key", "1"));
Assert.True(db.CMS().Info("cms-key").Width == 100);
Assert.True(db.CF().Info("cf-key").Size > 0);
Assert.True(db.GRAPH().List().Count > 0);
Assert.False(db.JSON().Get("json-key").IsNull);
Assert.NotNull(db.FT().Info("ft-key"));
Assert.NotNull(db.TDIGEST().Info("tdigest-key"));
Assert.NotNull(db.TS().Info("ts-key"));
Assert.NotNull(db.TOPK().Info("topk-key"));
}
}
}