Skip to content

Commit 3a851a4

Browse files
Feature/support transaction (#79)
* added pipelineexamples and docs * adding pipelinewithAsync example * adding pipelinewithasync doc feedback changes * added transaction support * fixing docs and transactions methods * adding transaction test01 * adding transactions tests * fix test * fixes * add TestModulsTransaction --------- Co-authored-by: shacharPash <shachar.pashchur@redis.com>
1 parent 1f00360 commit 3a851a4

File tree

6 files changed

+238
-20
lines changed

6 files changed

+238
-20
lines changed
+16-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
# Combination modules Pipeline
2+
23
## An example of pipelines mixing a pipeline with a combination of module commands with JSON & Search
34

45
Connect to the Redis server:
6+
57
```csharp
68
var redis = ConnectionMultiplexer.Connect("localhost");
79
```
810

911
Setup pipeline connection
12+
1013
```csharp
1114
var db = redis.GetDatabase();
1215
var pipeline = new Pipeline(db);
1316
```
1417

1518
## JSON
19+
1620
Add JsonSet to pipeline
21+
1722
```csharp
1823
pipeline.Json.SetAsync("person:01", "$", new { name = "John", age = 30, city = "New York" });
1924
pipeline.Json.SetAsync("person:02", "$", new { name = "Joy", age = 25, city = "Los Angeles" });
@@ -23,27 +28,33 @@ pipeline.Json.SetAsync("person:05", "$", new { name = "Michael", age = 55, city
2328
```
2429

2530
## Search
31+
2632
Create the schema to index name as text field, age as a numeric field and city as tag field.
33+
2734
```csharp
2835
var schema = new Schema().AddTextField("name").AddNumericField("age", true).AddTagField("city");
2936
```
3037

3138
Filter the index to only include Jsons with prefix of person:
39+
3240
```csharp
3341
var parameters = FTCreateParams.CreateParams().On(IndexDataType.JSON).Prefix("person:");
3442
```
3543

3644
Create the index via pipeline
45+
3746
```csharp
3847
pipeline.Ft.CreateAsync("person-idx", parameters, schema);
3948
```
4049

41-
Search for all indexed person records
50+
Execute the pipeline
51+
4252
```csharp
43-
var getAllPersons = db.FT().SearchAsync("person-idx", new Query());
53+
pipeline.Execute();
4454
```
4555

46-
Execute the pipeline
56+
Search for all indexed person records
57+
4758
```csharp
48-
pipeline.Execute();
49-
```
59+
var getAllPersons = db.FT().SearchAsync("person-idx", new Query());
60+
```

Examples/TransactionsExample.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Transaction
2+
3+
## An example of transactions with Redis modules (JSON.SET, JSON.GET & JSON.NUMINCRBY)
4+
5+
Connect to the Redis server
6+
7+
```cs
8+
var redis = await ConnectionMultiplexer.ConnectAsync("localhost");
9+
var db = redis.GetDatabase();
10+
```
11+
12+
Setup transaction
13+
14+
```cs
15+
var tran = new Transactions(db);
16+
```
17+
18+
Add account details with Json.Set
19+
20+
```cs
21+
tran.Json.SetAsync("accdetails:Jeeva", "$", new { name = "Jeeva", totalAmount= 1000, bankName = "City" });
22+
tran.Json.SetAsync("accdetails:Shachar", "$", new { name = "Shachar", totalAmount = 1000, bankName = "City" });
23+
```
24+
25+
Get the Json response for both Jeeva & Shachar
26+
27+
```cs
28+
var getShachar = tran.Json.GetAsync("accdetails:Shachar");
29+
var getJeeva = tran.Json.GetAsync("accdetails:Jeeva");
30+
```
31+
32+
Debit 200 from Jeeva
33+
34+
```cs
35+
tran.Json.NumIncrbyAsync("accdetails:Jeeva", "$.totalAmount", -200);
36+
```
37+
38+
Credit 200 from Shachar
39+
40+
```cs
41+
tran.Json.NumIncrbyAsync("accdetails:Shachar", "$.totalAmount", 200);
42+
```
43+
44+
Get total amount for both Jeeva = 800 & Shachar = 1200
45+
46+
```cs
47+
var totalAmtOfJeeva = tran.Json.GetAsync("accdetails:Jeeva", path:"$.totalAmount");
48+
var totalAmtOfShachar = tran.Json.GetAsync("accdetails:Shachar", path:"$.totalAmount");
49+
```
50+
51+
Execute the transaction
52+
53+
```cs
54+
var condition = tran.ExecuteAsync();
55+
```

src/NRedisStack/Pipeline.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ public Pipeline(IDatabase db)
1111

1212
private IBatch _batch;
1313

14-
public void Execute()
15-
{
16-
_batch.Execute();
17-
}
14+
public void Execute() => _batch.Execute();
15+
1816

1917
public IBloomCommandsAsync Bf => new BloomCommandsAsync(_batch);
2018
public ICmsCommandsAsync Cms => new CmsCommandsAsync(_batch);

src/NRedisStack/Transactions.cs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using StackExchange.Redis;
2+
3+
namespace NRedisStack
4+
{
5+
public class Transactions
6+
{
7+
private ITransaction _transaction;
8+
public IDatabaseAsync Db => _transaction;
9+
10+
public Transactions(IDatabase db)
11+
{
12+
_transaction = db.CreateTransaction();
13+
}
14+
15+
public ConditionResult AddCondition(Condition condition) => _transaction.AddCondition(condition);
16+
17+
public bool Execute(CommandFlags flags = CommandFlags.None) => _transaction.Execute(flags);
18+
19+
public Task<bool> ExecuteAsync(CommandFlags flags = CommandFlags.None) => _transaction.ExecuteAsync(flags);
20+
21+
public IBloomCommandsAsync Bf => new BloomCommandsAsync(_transaction);
22+
public ICmsCommandsAsync Cms => new CmsCommandsAsync(_transaction);
23+
public ICuckooCommandsAsync Cf => new CuckooCommandsAsync(_transaction);
24+
public IGraphCommandsAsync Graph => new GraphCommandsAsync(_transaction);
25+
public IJsonCommandsAsync Json => new JsonCommandsAsync(_transaction);
26+
public ISearchCommandsAsync Ft => new SearchCommandsAsync(_transaction);
27+
public ITdigestCommandsAsync Tdigest => new TdigestCommandsAsync(_transaction);
28+
public ITimeSeriesCommandsAsync Ts => new TimeSeriesCommandsAsync(_transaction);
29+
public ITopKCommandsAsync TopK => new TopKCommandsAsync(_transaction);
30+
}
31+
}

tests/NRedisStack.Tests/Examples/ExamplesTests.cs

+45-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
using Xunit;
2-
using StackExchange.Redis;
3-
using NRedisStack.RedisStackCommands;
41
using Moq;
5-
using NRedisStack.Search.FT.CREATE;
6-
using NRedisStack.Search;
72
using NRedisStack.DataTypes;
83
using NRedisStack.Literals.Enums;
4+
using NRedisStack.RedisStackCommands;
5+
using NRedisStack.Search;
6+
using NRedisStack.Search.FT.CREATE;
7+
using StackExchange.Redis;
8+
using Xunit;
99

1010
namespace NRedisStack.Tests;
1111

@@ -81,8 +81,6 @@ public async Task AsyncExample()
8181
[Fact]
8282
public void PipelineExample()
8383
{
84-
// Connect to the Redis server and Setup 2 Pipelines
85-
8684
// Pipeline can get IDatabase for pipeline
8785
IDatabase db = redisFixture.Redis.GetDatabase();
8886
db.Execute("FLUSHALL");
@@ -103,7 +101,7 @@ public void PipelineExample()
103101
// Get the Json response
104102
var getResponse = pipeline.Json.GetAsync("person");
105103

106-
// Execute the pipeline2
104+
// Execute the pipeline
107105
pipeline.Execute();
108106

109107
// Get the result back JSON
@@ -168,8 +166,8 @@ public async Task PipelineWithAsync()
168166
var db = redis.GetDatabase();
169167
db.Execute("FLUSHALL");
170168
// Setup pipeline connection
171-
var pipeline = new Pipeline(db);
172169

170+
var pipeline = new Pipeline(db);
173171

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

218216
[Fact]
219-
public void TransactionExample()
217+
public async Task TransactionExample()
220218
{
221-
// implementation for transaction
219+
// Connect to the Redis server
220+
var redis = ConnectionMultiplexer.Connect("localhost");
221+
222+
// Get a reference to the database
223+
var db = redis.GetDatabase();
224+
db.Execute("FLUSHALL");
225+
226+
// Setup transaction with IDatabase
227+
var tran = new Transactions(db);
228+
229+
// Add account details with Json.Set to transaction
230+
tran.Json.SetAsync("accdetails:Jeeva", "$", new { name = "Jeeva", totalAmount= 1000, bankName = "City" });
231+
tran.Json.SetAsync("accdetails:Shachar", "$", new { name = "Shachar", totalAmount = 1000, bankName = "City" });
232+
233+
// Get the Json response
234+
var getShachar = tran.Json.GetAsync("accdetails:Shachar");
235+
var getJeeva = tran.Json.GetAsync("accdetails:Jeeva");
236+
237+
// Debit 200 from Jeeva
238+
tran.Json.NumIncrbyAsync("accdetails:Jeeva", "$.totalAmount", -200);
239+
240+
// Credit 200 from Shachar
241+
tran.Json.NumIncrbyAsync("accdetails:Shachar", "$.totalAmount", 200);
242+
243+
// Get total amount for both Jeeva = 800 & Shachar = 1200
244+
var totalAmtOfJeeva = tran.Json.GetAsync("accdetails:Jeeva", path:"$.totalAmount");
245+
var totalAmtOfShachar = tran.Json.GetAsync("accdetails:Shachar", path:"$.totalAmount");
246+
247+
// Execute the transaction
248+
var condition = tran.ExecuteAsync();
249+
250+
// Assert
251+
Assert.True(condition.Result);
252+
Assert.NotEmpty(getJeeva.Result.ToString());
253+
Assert.NotEmpty(getShachar.Result.ToString());
254+
Assert.Equal("[800]", totalAmtOfJeeva.Result.ToString());
255+
Assert.Equal("[1200]", totalAmtOfShachar.Result.ToString());
222256
}
223257
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using Moq;
2+
using NRedisStack.RedisStackCommands;
3+
using NRedisStack.Search;
4+
using NRedisStack.Search.FT.CREATE;
5+
using StackExchange.Redis;
6+
using System.Text.Json;
7+
using Xunit;
8+
9+
namespace NRedisStack.Tests
10+
{
11+
public class TransactionsTests : AbstractNRedisStackTest, IDisposable
12+
{
13+
Mock<IDatabase> _mock = new Mock<IDatabase>();
14+
private readonly string key = "TRX_TESTS";
15+
public TransactionsTests(RedisFixture redisFixture) : base(redisFixture) { }
16+
17+
public void Dispose()
18+
{
19+
redisFixture.Redis.GetDatabase().KeyDelete(key);
20+
}
21+
22+
[Fact]
23+
public async Task TestJsonTransactions()
24+
{
25+
IDatabase db = redisFixture.Redis.GetDatabase();
26+
db.Execute("FLUSHALL");
27+
var transaction = new Transactions(db);
28+
string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 });
29+
var setResponse = transaction.Json.SetAsync(key, "$", jsonPerson);
30+
var getResponse = transaction.Json.GetAsync(key);
31+
32+
transaction.Execute();
33+
34+
Assert.Equal("True", setResponse.Result.ToString());
35+
Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString());
36+
}
37+
38+
[Fact]
39+
public async Task TestModulsTransaction()
40+
{
41+
IDatabase db = redisFixture.Redis.GetDatabase();
42+
db.Execute("FLUSHALL");
43+
var tran = new Transactions(db);
44+
45+
tran.Bf.ReserveAsync("bf-key", 0.001, 100);
46+
tran.Bf.AddAsync("bf-key", "1");
47+
tran.Cms.InitByDimAsync("cms-key", 100, 5);
48+
tran.Cf.ReserveAsync("cf-key", 100);
49+
tran.Graph.QueryAsync("graph-key", "CREATE ({name:'shachar',age:23})");
50+
tran.Json.SetAsync("json-key", "$", "{}");
51+
tran.Ft.CreateAsync("ft-key", new FTCreateParams(), new Schema().AddTextField("txt"));
52+
tran.Tdigest.CreateAsync("tdigest-key", 100);
53+
tran.Ts.CreateAsync("ts-key", 100);
54+
tran.TopK.ReserveAsync("topk-key", 100, 100, 100);
55+
56+
Assert.False(db.KeyExists("bf-key"));
57+
Assert.False(db.KeyExists("cms-key"));
58+
Assert.False(db.KeyExists("cf-key"));
59+
Assert.False(db.KeyExists("graph-key"));
60+
Assert.False(db.KeyExists("json-key"));
61+
Assert.Equal(0, db.FT()._List().Length);
62+
Assert.False(db.KeyExists("tdigest-key"));
63+
Assert.False(db.KeyExists("ts-key"));
64+
Assert.False(db.KeyExists("topk-key"));
65+
66+
tran.Execute();
67+
68+
Assert.True(db.KeyExists("bf-key"));
69+
Assert.True(db.KeyExists("cms-key"));
70+
Assert.True(db.KeyExists("cf-key"));
71+
Assert.True(db.KeyExists("graph-key"));
72+
Assert.True(db.KeyExists("json-key"));
73+
Assert.True(db.FT()._List().Length == 1);
74+
Assert.True(db.KeyExists("tdigest-key"));
75+
Assert.True(db.KeyExists("ts-key"));
76+
Assert.True(db.KeyExists("topk-key"));
77+
78+
Assert.True(db.BF().Exists("bf-key", "1"));
79+
Assert.True(db.CMS().Info("cms-key").Width == 100);
80+
Assert.True(db.CF().Info("cf-key").Size > 0);
81+
Assert.True(db.GRAPH().List().Count > 0);
82+
Assert.False(db.JSON().Get("json-key").IsNull);
83+
Assert.NotNull(db.FT().Info("ft-key"));
84+
Assert.NotNull(db.TDIGEST().Info("tdigest-key"));
85+
Assert.NotNull(db.TS().Info("ts-key"));
86+
Assert.NotNull(db.TOPK().Info("topk-key"));
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)