├── .gitignore
├── NRedisTimeSeries.Example
├── NRedisTimeSeries.Example.csproj
├── GetExample.cs
├── GetExampleAsync.cs
├── RulesExampleAsync.cs
├── RulesExample.cs
├── AlterExample.cs
├── AlterExampleAsync.cs
├── MAddExample.cs
├── MAddExampleAsync.cs
├── InfoQueryIndexExample.cs
├── CreateExample.cs
├── InfoQueryIndexExampleAsync.cs
├── CreateExampleAsync.cs
├── MGetExample.cs
├── MGetExampleAsync.cs
├── IncrByExample.cs
├── DecrByExample.cs
├── IncrByExampleAsync.cs
├── DecrByExampleAsync.cs
├── AddExample.cs
├── AddExampleAsync.cs
├── RangeExample.cs
├── RangeExampleAsync.cs
├── MRangeExample.cs
└── MRangeExampleAsync.cs
├── NRedisTimeSeries.Test
├── TestAPI
│ ├── RedisFixture.cs
│ ├── TestQueryIndexAsync.cs
│ ├── TestQueryIndex.cs
│ ├── TestGet.cs
│ ├── TestGetAsync.cs
│ ├── TestAlterAsync.cs
│ ├── TestAlter.cs
│ ├── TestDel.cs
│ ├── TestDelAsync.cs
│ ├── AbstractTimeSeriesTest.cs
│ ├── TestMGetAsync.cs
│ ├── TestMGet.cs
│ ├── TestIncrBy.cs
│ ├── TestDecrBy.cs
│ ├── TestRulesAsync.cs
│ ├── TestCreate.cs
│ ├── TestMAddAsync.cs
│ ├── TestMADD.cs
│ ├── TestCreateAsync.cs
│ ├── TestIncrByAsync.cs
│ ├── TestDecrByAsync.cs
│ ├── TestRules.cs
│ ├── TestRange.cs
│ ├── TestRevRange.cs
│ ├── TestRangeAsync.cs
│ ├── TestRevRangeAsync.cs
│ └── TestAdd.cs
├── NRedisTimeSeries.Test.csproj
└── TestDataTypes
│ ├── TestTimeStamp.cs
│ ├── TestTimeSeriesInformation.cs
│ ├── TestTimeSeriesTuple.cs
│ ├── TestTimeSeriesLabel.cs
│ └── TestTimeSeriesRule.cs
├── .github
├── release-drafter-config.yml
└── workflows
│ └── release-drafter.yml
├── NRedisTimeSeries
├── Commands
│ ├── Enums
│ │ ├── Reduce.cs
│ │ ├── DuplicatePolicy.cs
│ │ └── Aggregation.cs
│ ├── Commands.cs
│ └── CommandArgs.cs
├── Extensions
│ ├── ReduceExtensions.cs
│ ├── DuplicatePolicyExtensions.cs
│ └── AggregationExtensions.cs
├── NRedisTimeSeries.csproj
├── DataTypes
│ ├── TimeSeriesLabel.cs
│ ├── TimeSeriesTuple.cs
│ ├── TimeSeriesRule.cs
│ ├── TimeSeriesInformation.cs
│ └── TimeStamp.cs
└── TimeSeriesClientResponseParser.cs
├── LICENSE
├── README.md
└── NRedisTimeSeries.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs/
2 | .vscode/
3 | Docs/
4 | **/bin
5 | **/obj
6 | NRedisTimeSeries.Test/TestResults/
7 |
8 | # JetBrains related IDEs
9 | .idea/
10 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/NRedisTimeSeries.Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | 1.4.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/RedisFixture.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using StackExchange.Redis;
3 |
4 | namespace NRedisTimeSeries.Test.TestAPI
5 | {
6 | public class RedisFixture : IDisposable
7 | {
8 | public RedisFixture() => Redis = ConnectionMultiplexer.Connect("localhost");
9 |
10 | public void Dispose()
11 | {
12 | Redis.Close();
13 | }
14 |
15 | public ConnectionMultiplexer Redis { get; private set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.github/release-drafter-config.yml:
--------------------------------------------------------------------------------
1 | name-template: 'Version $NEXT_PATCH_VERSION'
2 | tag-template: 'v$NEXT_PATCH_VERSION'
3 | categories:
4 | - title: 'Features'
5 | labels:
6 | - 'feature'
7 | - 'enhancement'
8 | - title: 'Bug Fixes'
9 | labels:
10 | - 'fix'
11 | - 'bugfix'
12 | - 'bug'
13 | - title: 'Maintenance'
14 | label: 'chore'
15 | change-template: '- $TITLE (#$NUMBER)'
16 | exclude-labels:
17 | - 'skip-changelog'
18 | template: |
19 | ## Changes
20 |
21 | $CHANGES
22 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Commands/Enums/Reduce.cs:
--------------------------------------------------------------------------------
1 | namespace NRedisTimeSeries.Commands.Enums
2 | {
3 | ///
4 | /// TODO: Add description
5 | ///
6 | public enum TsReduce
7 | {
8 | ///
9 | /// A sum of all samples in the group
10 | ///
11 | Sum,
12 |
13 | ///
14 | /// A minimum sample of all samples in the group
15 | ///
16 | Min,
17 |
18 | ///
19 | /// A maximum sample of all samples in the group
20 | ///
21 | Max,
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.github/workflows/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name: Release Drafter
2 |
3 | on:
4 | push:
5 | # branches to consider in the event; optional, defaults to all
6 | branches:
7 | - master
8 |
9 | jobs:
10 | update_release_draft:
11 | runs-on: ubuntu-latest
12 | steps:
13 | # Drafts your next Release notes as Pull Requests are merged into "master"
14 | - uses: release-drafter/release-drafter@v5
15 | with:
16 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
17 | config-name: release-drafter-config.yml
18 | env:
19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/NRedisTimeSeries.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | false
6 | 1.4.0
7 |
8 |
9 |
10 |
11 |
12 |
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 | all
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/GetExample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.DataTypes;
3 | using StackExchange.Redis;
4 |
5 | namespace NRedisTimeSeries.Example
6 | {
7 | ///
8 | /// Examples for NRedisTimeSeries API for GET queries.
9 | ///
10 | internal class GetExample
11 | {
12 | ///
13 | /// Example for GET query. The NRedisTimeSeries TimeSeriesGet command returns a TimeSeriesTuple object.
14 | ///
15 | public static void SimpleGetExample()
16 | {
17 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
18 | IDatabase db = redis.GetDatabase();
19 | TimeSeriesTuple value = db.TimeSeriesGet("my_ts");
20 | Console.WriteLine(value);
21 | redis.Close();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Extensions/ReduceExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.Commands.Enums;
3 |
4 | namespace NRedisTimeSeries.Extensions
5 | {
6 | internal static class ReduceExtensions
7 | {
8 | public static string AsArg(this TsReduce reduce) => reduce switch
9 | {
10 | TsReduce.Sum => "SUM",
11 | TsReduce.Min => "MIN",
12 | TsReduce.Max => "MAX",
13 | _ => throw new ArgumentOutOfRangeException(nameof(reduce), "Invalid Reduce type"),
14 | };
15 |
16 | public static TsReduce AsReduce(string reduce) => reduce switch
17 | {
18 | "SUM" => TsReduce.Sum,
19 | "MIN" => TsReduce.Min,
20 | "MAX" => TsReduce.Max,
21 | _ => throw new ArgumentOutOfRangeException(nameof(reduce), $"Invalid Reduce type '{reduce}'"),
22 | };
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestDataTypes/TestTimeStamp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.DataTypes;
3 | using Xunit;
4 | namespace NRedisTimeSeries.Test
5 | {
6 | public class TestTimeStamp
7 | {
8 |
9 | [Fact]
10 | public void TestTimeStampImplicitCast()
11 | {
12 | TimeStamp ts = 1;
13 | Assert.Equal(1, ts);
14 |
15 | ts = "+";
16 | Assert.Equal("+", ts);
17 |
18 | ts = "*";
19 | Assert.Equal("*", ts);
20 |
21 | ts = "-";
22 | Assert.Equal("-", ts);
23 |
24 | var ex = Assert.Throws(() => ts = "hi");
25 | Assert.Equal("The string hi cannot be used", ex.Message);
26 |
27 | DateTime now = DateTime.UtcNow;
28 | ts = now;
29 | Assert.Equal(now, ts);
30 |
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/GetExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System.Threading.Tasks;
4 | using System;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries async API for GET queries.
10 | ///
11 | internal class GetAsyncExample
12 | {
13 | ///
14 | /// Example for GET query. The NRedisTimeSeries TimeSeriesGet command returns a TimeSeriesTuple object.
15 | ///
16 | public static async Task SimpleGetAsyncExample()
17 | {
18 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
19 | IDatabase db = redis.GetDatabase();
20 | TimeSeriesTuple value = await db.TimeSeriesGetAsync("my_ts");
21 | Console.WriteLine(value);
22 | redis.Close();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/NRedisTimeSeries.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | 8.0
6 | 1.4.0
7 | Dvir Dukhan
8 | Redis Labs
9 | .Net Client for RedisTimeSeries
10 | 1.4.0
11 |
12 |
13 |
14 |
15 |
16 |
17 | ../Docs/NRedisTimeSeries.xml
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Commands/Commands.cs:
--------------------------------------------------------------------------------
1 | namespace NRedisTimeSeries.Commands
2 | {
3 | internal class TS
4 | {
5 | public static string CREATE => "TS.CREATE";
6 | public static string ALTER => "TS.ALTER";
7 | public static string ADD => "TS.ADD";
8 | public static string MADD => "TS.MADD";
9 | public static string INCRBY => "TS.INCRBY";
10 | public static string DECRBY => "TS.DECRBY";
11 | public static string DEL => "TS.DEL";
12 | public static string CREATERULE => "TS.CREATERULE";
13 | public static string DELETERULE => "TS.DELETERULE";
14 | public static string RANGE => "TS.RANGE";
15 | public static string REVRANGE => "TS.REVRANGE";
16 | public static string MRANGE => "TS.MRANGE";
17 | public static string MREVRANGE => "TS.MREVRANGE";
18 | public static string GET => "TS.GET";
19 | public static string MGET => "TS.MGET";
20 | public static string INFO => "TS.INFO";
21 | public static string QUERYINDEX => "TS.QUERYINDEX";
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/RulesExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using StackExchange.Redis;
3 | using NRedisTimeSeries.Commands.Enums;
4 | using NRedisTimeSeries.DataTypes;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries async API creating and deleting rules.
10 | ///
11 | internal class RulesAsyncExample
12 | {
13 | ///
14 | /// Example for create and delete RedisTimeSeries rules.
15 | ///
16 | public static async Task RulesCreateDeleteAsyncExample()
17 | {
18 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
19 | IDatabase db = redis.GetDatabase();
20 | // Create your rule with destination key, time bucket and aggregation type.
21 | TimeSeriesRule rule = new TimeSeriesRule("dest_ts", 50, TsAggregation.Avg);
22 | await db.TimeSeriesCreateRuleAsync("my_ts", rule);
23 | await db.TimeSeriesDeleteRuleAsync("my_ts", "dest");
24 | redis.Close();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Commands/CommandArgs.cs:
--------------------------------------------------------------------------------
1 | namespace NRedisTimeSeries.Commands
2 | {
3 | internal class CommandArgs
4 | {
5 | public static string RETENTION => "RETENTION";
6 | public static string LABELS => "LABELS";
7 | public static string UNCOMPRESSED => "UNCOMPRESSED";
8 | public static string COUNT => "COUNT";
9 | public static string AGGREGATION => "AGGREGATION";
10 | public static string ALIGN => "ALIGN";
11 | public static string FILTER => "FILTER";
12 | public static string WITHLABELS => "WITHLABELS";
13 | public static string SELECTEDLABELS => "SELECTED_LABELS";
14 | public static string TIMESTAMP => "TIMESTAMP";
15 | public static string CHUNK_SIZE => "CHUNK_SIZE";
16 | public static string DUPLICATE_POLICY => "DUPLICATE_POLICY";
17 | public static string ON_DUPLICATE => "ON_DUPLICATE";
18 | public static string GROPUBY => "GROUPBY";
19 | public static string REDUCE => "REDUCE";
20 | public static string FILTER_BY_TS => "FILTER_BY_TS";
21 | public static string FILTER_BY_VALUE => "FILTER_BY_VALUE";
22 |
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/RulesExample.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.Commands.Enums;
2 | using NRedisTimeSeries.DataTypes;
3 | using StackExchange.Redis;
4 |
5 | namespace NRedisTimeSeries.Example
6 | {
7 | ///
8 | /// Example for create and delete RedisTimeSeries rules.
9 | ///
10 | internal class RulesExample
11 | {
12 | ///
13 | /// Example for create and delete RedisTimeSeries rules.
14 | ///
15 | public static void RulesCreateDeleteExample()
16 | {
17 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
18 | IDatabase db = redis.GetDatabase();
19 | // Create new timeseries for the sourceKey and the destKey.
20 | db.TimeSeriesCreate("my_ts");
21 | db.TimeSeriesCreate("dest_ts");
22 | // Create your rule with destination key, time bucket and aggregation type.
23 | TimeSeriesRule rule = new TimeSeriesRule("dest_ts", 50, TsAggregation.Avg);
24 | db.TimeSeriesCreateRule("my_ts", rule);
25 | db.TimeSeriesDeleteRule("my_ts", "dest_ts");
26 | redis.Close();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/AlterExample.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NRedisTimeSeries.DataTypes;
3 | using StackExchange.Redis;
4 |
5 | namespace NRedisTimeSeries.Example
6 | {
7 | ///
8 | /// Examples for NRedisTimeSeries API for altering time series properties.
9 | ///
10 | internal class AlterExample
11 | {
12 | ///
13 | /// Examples for altering time-series.
14 | /// The parameters retentionTime, and labels are optional and can be set in any order when used as named argument.
15 | ///
16 | public static void ParameterizedAlter()
17 | {
18 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
19 | IDatabase db = redis.GetDatabase();
20 | var label = new TimeSeriesLabel("key", "value");
21 | var labels = new List { label };
22 | db.TimeSeriesAlter("labeld_ts", labels: labels);
23 | db.TimeSeriesAlter("retention_time_ts", retentionTime: 5000);
24 | db.TimeSeriesAlter("parameterized_ts", retentionTime: 5000, labels: labels);
25 | redis.Close();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestQueryIndexAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Xunit;
5 |
6 | namespace NRedisTimeSeries.Test.TestAPI
7 | {
8 | public class TestQueryIndexAsync : AbstractTimeSeriesTest
9 | {
10 | public TestQueryIndexAsync(RedisFixture redisFixture) : base(redisFixture) { }
11 |
12 | [Fact]
13 | public async Task TestTSQueryIndex()
14 | {
15 | var keys = CreateKeyNames(2);
16 | var db = redisFixture.Redis.GetDatabase();
17 | var label1 = new TimeSeriesLabel(keys[0], "value");
18 | var label2 = new TimeSeriesLabel(keys[1], "value2");
19 | var labels1 = new List { label1, label2 };
20 | var labels2 = new List { label1 };
21 |
22 | await db.TimeSeriesCreateAsync(keys[0], labels: labels1);
23 | await db.TimeSeriesCreateAsync(keys[1], labels: labels2);
24 | Assert.Equal(keys, db.TimeSeriesQueryIndex(new List { $"{keys[0]}=value" }));
25 | Assert.Equal(new List { keys[0] }, db.TimeSeriesQueryIndex(new List { $"{keys[1]}=value2" }));
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Extensions/DuplicatePolicyExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.Commands.Enums;
3 |
4 | namespace NRedisTimeSeries.Extensions
5 | {
6 | internal static class DuplicatePolicyExtensions
7 | {
8 | public static string AsArg(this TsDuplicatePolicy policy) => policy switch
9 | {
10 | TsDuplicatePolicy.BLOCK => "BLOCK",
11 | TsDuplicatePolicy.FIRST => "FIRST",
12 | TsDuplicatePolicy.LAST => "LAST",
13 | TsDuplicatePolicy.MIN => "MIN",
14 | TsDuplicatePolicy.MAX => "MAX",
15 | TsDuplicatePolicy.SUM => "SUM",
16 | _ => throw new ArgumentOutOfRangeException(nameof(policy), "Invalid policy type"),
17 | };
18 |
19 | public static TsDuplicatePolicy AsPolicy(string policy) => policy switch
20 | {
21 | "BLOCK" => TsDuplicatePolicy.BLOCK,
22 | "FIRST" => TsDuplicatePolicy.FIRST,
23 | "LAST" => TsDuplicatePolicy.LAST,
24 | "MIN" => TsDuplicatePolicy.MIN,
25 | "MAX" => TsDuplicatePolicy.MAX,
26 | "SUM" => TsDuplicatePolicy.SUM,
27 | _ => throw new ArgumentOutOfRangeException(nameof(policy), $"Invalid policy type '{policy}'"),
28 | };
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Commands/Enums/DuplicatePolicy.cs:
--------------------------------------------------------------------------------
1 | namespace NRedisTimeSeries.Commands.Enums
2 | {
3 | ///
4 | /// Policy to handle duplicate samples.
5 | /// The default policy for database-wide is BLOCK.
6 | ///
7 | public enum TsDuplicatePolicy
8 | {
9 | ///
10 | /// An error will occur for any out of order sample.
11 | ///
12 | BLOCK,
13 |
14 | ///
15 | /// Ignore the new value.
16 | ///
17 | FIRST,
18 |
19 | ///
20 | /// Override with latest value.
21 | ///
22 | LAST,
23 |
24 | ///
25 | /// Only override if the value is lower than the existing value.
26 | ///
27 | MIN,
28 |
29 | ///
30 | /// Only override if the value is higher than the existing value.
31 | ///
32 | MAX,
33 |
34 | ///
35 | /// If a previous sample exists, add the new sample to it so that the updated value is equal to (previous + new).
36 | /// If no previous sample exists, set the updated value equal to the new value.
37 | ///
38 | SUM
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/AlterExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries async API for altering time series properties.
10 | ///
11 | internal class AlterAsyncExample
12 | {
13 | ///
14 | /// Examples for altering time-series.
15 | /// The parameters retentionTime, and labels are optional and can be set in any order when used as named argument.
16 | ///
17 | public static async Task ParameterizedAlterAsync()
18 | {
19 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
20 | IDatabase db = redis.GetDatabase();
21 | var label = new TimeSeriesLabel("key", "value");
22 | var labels = new List { label };
23 | await db.TimeSeriesAlterAsync("labeld_ts", labels: labels);
24 | await db.TimeSeriesAlterAsync("retention_time_ts", retentionTime: 5000);
25 | await db.TimeSeriesAlterAsync("parameterized_ts", retentionTime: 5000, labels: labels);
26 | redis.Close();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestDataTypes/TestTimeSeriesInformation.cs:
--------------------------------------------------------------------------------
1 | using StackExchange.Redis;
2 | using NRedisTimeSeries.DataTypes;
3 | using NRedisTimeSeries.Commands.Enums;
4 | using NRedisTimeSeries.Test.TestAPI;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 |
8 | namespace NRedisTimeSeries.Test.TestDataTypes
9 | {
10 | public class TestInformation : AbstractTimeSeriesTest
11 | {
12 | public TestInformation(RedisFixture redisFixture) : base(redisFixture) { }
13 |
14 | [Fact]
15 | public async Task TestInformationToStringAsync()
16 | {
17 | string key = CreateKeyName();
18 | IDatabase db = redisFixture.Redis.GetDatabase();
19 | await db.TimeSeriesAddAsync(key, "*", 1.1);
20 | await db.TimeSeriesAddAsync(key, "*", 1.3, duplicatePolicy: TsDuplicatePolicy.LAST);
21 | TimeSeriesInformation info = await db.TimeSeriesInfoAsync(key);
22 | string[] infoProperties = ((string)info).Trim('{').Trim('}').Split(",");
23 | Assert.Equal("\"TotalSamples\":2", infoProperties[0]);
24 | Assert.Equal("\"MemoryUsage\":4184", infoProperties[1]);
25 | Assert.Equal("\"RetentionTime\":0", infoProperties[4]);
26 | Assert.Equal("\"ChunkCount\":1", infoProperties[5]);
27 | Assert.Equal("\"DuplicatePolicy\":null", infoProperties[11]);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/MAddExample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries API for adding multiple samples to multiple time series.
10 | ///
11 | internal class MAddExample
12 | {
13 | ///
14 | /// Example for mutiple sample addtion. One is using RedisTimeSeris default system time in one time series,
15 | /// the second is using DateTime in the second time series and the third is using long in the third time series.
16 | ///
17 | public static void MAddFlowExample()
18 | {
19 | string[] keys = { "system_time_ts", "datetime_ts", "long_ts" };
20 | var sequence = new List<(string, TimeStamp, double)>(keys.Length);
21 | // Add sample to the system_time_ts
22 | sequence.Add((keys[0], "*", 0.0));
23 | // Add sample to the datetime_ts
24 | sequence.Add((keys[1], DateTime.UtcNow, 0.0));
25 | // Add sample to the long_ts
26 | sequence.Add((keys[2], 1, 0.0));
27 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
28 | IDatabase db = redis.GetDatabase();
29 | db.TimeSeriesMAdd(sequence);
30 | redis.Close();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestQueryIndex.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using Xunit;
5 |
6 | namespace NRedisTimeSeries.Test.TestAPI
7 | {
8 | public class TestQueryIndex : AbstractTimeSeriesTest, IDisposable
9 | {
10 | private readonly string[] keys = { "QUERYINDEX_TESTS_1", "QUERYINDEX_TESTS_2" };
11 |
12 | public TestQueryIndex(RedisFixture redisFixture) : base(redisFixture) { }
13 |
14 | public void Dispose()
15 | {
16 | foreach (var key in keys)
17 | {
18 | redisFixture.Redis.GetDatabase().KeyDelete(key);
19 | }
20 | }
21 |
22 | [Fact]
23 | public void TestTSQueryIndex()
24 | {
25 | var db = redisFixture.Redis.GetDatabase();
26 | var label1 = new TimeSeriesLabel("QUERYINDEX_TESTS_1", "value");
27 | var label2 = new TimeSeriesLabel("QUERYINDEX_TESTS_2", "value2");
28 | var labels1 = new List { label1, label2 };
29 | var labels2 = new List { label1 };
30 |
31 | db.TimeSeriesCreate(keys[0], labels: labels1);
32 | db.TimeSeriesCreate(keys[1], labels: labels2);
33 | Assert.Equal(keys, db.TimeSeriesQueryIndex(new List { "QUERYINDEX_TESTS_1=value" }));
34 | Assert.Equal(new List { keys[0] }, db.TimeSeriesQueryIndex(new List { "QUERYINDEX_TESTS_2=value2" }));
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/MAddExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using NRedisTimeSeries.DataTypes;
5 | using StackExchange.Redis;
6 |
7 | namespace NRedisTimeSeries.Example
8 | {
9 | ///
10 | /// Examples for NRedisTimeSeries async API for adding multiple samples to multiple time series.
11 | ///
12 | internal class MAddAsyncExample
13 | {
14 | ///
15 | /// Example for mutiple sample addtion. One is using RedisTimeSeris default system time in one time series,
16 | /// the second is using DateTime in the second time series and the third is using long in the third time series.
17 | ///
18 | public static async Task MAddFlowAsyncExample()
19 | {
20 | string[] keys = { "system_time_ts", "datetime_ts", "long_ts" };
21 | var sequence = new List<(string, TimeStamp, double)>(keys.Length);
22 | // Add sample to the system_time_ts
23 | sequence.Add((keys[0], "*", 0.0));
24 | // Add sample to the datetime_ts
25 | sequence.Add((keys[1], DateTime.UtcNow, 0.0));
26 | // Add sample to the long_ts
27 | sequence.Add((keys[2], 1, 0.0));
28 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
29 | IDatabase db = redis.GetDatabase();
30 | await db.TimeSeriesMAddAsync(sequence);
31 | redis.Close();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestDataTypes/TestTimeSeriesTuple.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.DataTypes;
3 | using Xunit;
4 |
5 | namespace NRedisTimeSeries.Test
6 | {
7 | public class TestTimeSeriesTuple
8 | {
9 | [Fact]
10 | public void TestTupleConstructor()
11 | {
12 | TimeSeriesTuple tuple = new TimeSeriesTuple(1, 1.1);
13 | Assert.Equal(1, tuple.Time);
14 | Assert.Equal(1.1, tuple.Val);
15 | }
16 |
17 | [Fact]
18 | public void TestTupleEqual()
19 | {
20 | TimeSeriesTuple tuple1 = new TimeSeriesTuple(1, 1.1);
21 | TimeSeriesTuple tuple1_1 = new TimeSeriesTuple(1, 1.1);
22 | TimeSeriesTuple tuple1_2 = new TimeSeriesTuple(2, 2.2);
23 | Assert.Equal(tuple1, tuple1_1);
24 | Assert.NotEqual(tuple1, tuple1_2);
25 | }
26 |
27 | [Fact]
28 | public void TestTupleHashCode()
29 | {
30 | TimeSeriesTuple tuple1 = new TimeSeriesTuple(1, 1.1);
31 | TimeSeriesTuple tuple1_1 = new TimeSeriesTuple(1, 1.1);
32 | TimeSeriesTuple tuple1_2 = new TimeSeriesTuple(2, 2.2);
33 | Assert.Equal(tuple1.GetHashCode(), tuple1_1.GetHashCode());
34 | Assert.NotEqual(tuple1.GetHashCode(), tuple1_2.GetHashCode());
35 | }
36 |
37 | [Fact]
38 | public void TestTupleToString()
39 | {
40 | TimeSeriesTuple tuple = new TimeSeriesTuple(1, 1.1);
41 | Assert.Equal("Time: 1, Val:1.1", (string)tuple);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2020, RedisTimeSeries
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestGet.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System;
4 | using Xunit;
5 |
6 | namespace NRedisTimeSeries.Test.TestAPI
7 | {
8 | public class TestGet : AbstractTimeSeriesTest, IDisposable
9 | {
10 |
11 | private readonly string key = "GET_TESTS";
12 |
13 | public TestGet(RedisFixture redisFixture) : base(redisFixture) { }
14 |
15 | public void Dispose()
16 | {
17 | redisFixture.Redis.GetDatabase().KeyDelete(key);
18 | }
19 |
20 | [Fact]
21 | public void TestGetNotExists()
22 | {
23 | IDatabase db = redisFixture.Redis.GetDatabase();
24 | var ex = Assert.Throws(()=>db.TimeSeriesGet(key));
25 | Assert.Equal("ERR TSDB: the key does not exist", ex.Message);
26 | }
27 |
28 | [Fact]
29 | public void TestEmptyGet()
30 | {
31 | IDatabase db = redisFixture.Redis.GetDatabase();
32 | db.TimeSeriesCreate(key);
33 | Assert.Null(db.TimeSeriesGet(key));
34 | }
35 |
36 | [Fact]
37 | public void TestAddAndGet()
38 | {
39 | DateTime now = DateTime.UtcNow;
40 | TimeSeriesTuple expected = new TimeSeriesTuple(now, 1.1);
41 | IDatabase db = redisFixture.Redis.GetDatabase();
42 | db.TimeSeriesCreate(key);
43 | db.TimeSeriesAdd(key, now, 1.1);
44 | TimeSeriesTuple actual = db.TimeSeriesGet(key);
45 | Assert.Equal(expected, actual);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestGetAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System;
4 | using System.Threading.Tasks;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestAPI
8 | {
9 | public class TestGetAsync : AbstractTimeSeriesTest
10 | {
11 | public TestGetAsync(RedisFixture redisFixture) : base(redisFixture) { }
12 |
13 | [Fact]
14 | public async Task TestGetNotExists()
15 | {
16 | var key = CreateKeyName();
17 | var db = redisFixture.Redis.GetDatabase();
18 | var ex = await Assert.ThrowsAsync(async () => await db.TimeSeriesGetAsync(key));
19 | Assert.Equal("ERR TSDB: the key does not exist", ex.Message);
20 | }
21 |
22 | [Fact]
23 | public async Task TestEmptyGet()
24 | {
25 | var key = CreateKeyName();
26 | var db = redisFixture.Redis.GetDatabase();
27 | await db.TimeSeriesCreateAsync(key);
28 | Assert.Null(await db.TimeSeriesGetAsync(key));
29 | }
30 |
31 | [Fact]
32 | public async Task TestAddAndGet()
33 | {
34 | var key = CreateKeyName();
35 | var now = DateTime.UtcNow;
36 | var expected = new TimeSeriesTuple(now, 1.1);
37 | var db = redisFixture.Redis.GetDatabase();
38 | await db.TimeSeriesCreateAsync(key);
39 | await db.TimeSeriesAddAsync(key, now, 1.1);
40 | var actual = await db.TimeSeriesGetAsync(key);
41 | Assert.Equal(expected, actual);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/InfoQueryIndexExample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries API for INFO and QUERYINDEX commands.
10 | ///
11 | internal class InfoQueryIndexExample
12 | {
13 | ///
14 | /// Example for getting the information of a timeseries key with INFO command.
15 | ///
16 | public static void InfoExample()
17 | {
18 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
19 | IDatabase db = redis.GetDatabase();
20 | TimeSeriesInformation info = db.TimeSeriesInfo("my_ts");
21 | // Now you can access to all the properties of TimeSeriesInformation
22 | Console.WriteLine(info.TotalSamples);
23 | Console.WriteLine((string)info.FirstTimeStamp);
24 | Console.WriteLine((string)info.LastTimeStamp);
25 | redis.Close();
26 | }
27 |
28 | ///
29 | /// Example for using QUERYINDEX.
30 | ///
31 | public static void QueryIndexExample()
32 | {
33 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
34 | IDatabase db = redis.GetDatabase();
35 | var filter = new List { "key=value" };
36 | IReadOnlyList keys = db.TimeSeriesQueryIndex(filter);
37 | foreach(var key in keys) {
38 | Console.WriteLine(key);
39 | }
40 | redis.Close();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestAlterAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Xunit;
5 |
6 | namespace NRedisTimeSeries.Test.TestAPI
7 | {
8 | public class TestAlterAsync : AbstractTimeSeriesTest
9 | {
10 | public TestAlterAsync(RedisFixture redisFixture) : base(redisFixture) { }
11 |
12 | [Fact]
13 | public async Task TestAlterRetentionTime()
14 | {
15 | var key = CreateKeyName();
16 | long retentionTime = 5000;
17 | var db = redisFixture.Redis.GetDatabase();
18 | await db.TimeSeriesCreateAsync(key);
19 | Assert.True(await db.TimeSeriesAlterAsync(key, retentionTime: retentionTime));
20 |
21 | var info = await db.TimeSeriesInfoAsync(key);
22 | Assert.Equal(retentionTime, info.RetentionTime);
23 | }
24 |
25 | [Fact]
26 | public async Task TestAlterLabels()
27 | {
28 | var key = CreateKeyName();
29 | var db = redisFixture.Redis.GetDatabase();
30 | var label = new TimeSeriesLabel("key", "value");
31 | var labels = new List { label };
32 | await db.TimeSeriesCreateAsync(key);
33 | Assert.True(await db.TimeSeriesAlterAsync(key, labels: labels));
34 |
35 | var info = await db.TimeSeriesInfoAsync(key);
36 | Assert.Equal(labels, info.Labels);
37 |
38 | labels.Clear();
39 | Assert.True(await db.TimeSeriesAlterAsync(key, labels: labels));
40 |
41 | info = await db.TimeSeriesInfoAsync(key);
42 | Assert.Equal(labels, info.Labels);
43 | }
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestAlter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestAPI
8 | {
9 | public class TestAlter : AbstractTimeSeriesTest, IDisposable
10 | {
11 | private readonly string key = "ALTER_TESTS";
12 |
13 | public TestAlter(RedisFixture redisFixture): base(redisFixture) { }
14 |
15 | public void Dispose()
16 | {
17 | redisFixture.Redis.GetDatabase().KeyDelete(key);
18 | }
19 |
20 | [Fact]
21 | public void TestAlterRetentionTime()
22 | {
23 | long retentionTime = 5000;
24 | IDatabase db = redisFixture.Redis.GetDatabase();
25 | db.TimeSeriesCreate(key);
26 | Assert.True(db.TimeSeriesAlter(key, retentionTime: retentionTime));
27 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
28 | Assert.Equal(retentionTime, info.RetentionTime);
29 | }
30 |
31 | [Fact]
32 | public void TestAlterLabels()
33 | {
34 | TimeSeriesLabel label = new TimeSeriesLabel("key", "value");
35 | var labels = new List { label };
36 | IDatabase db = redisFixture.Redis.GetDatabase();
37 | db.TimeSeriesCreate(key);
38 | Assert.True(db.TimeSeriesAlter(key, labels: labels));
39 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
40 | Assert.Equal(labels, info.Labels);
41 | labels.Clear();
42 | Assert.True(db.TimeSeriesAlter(key, labels: labels));
43 | info = db.TimeSeriesInfo(key);
44 | Assert.Equal(labels, info.Labels);
45 | }
46 |
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Extensions/AggregationExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.Commands.Enums;
3 |
4 | namespace NRedisTimeSeries.Extensions
5 | {
6 | internal static class AggregationExtensions
7 | {
8 | public static string AsArg(this TsAggregation aggregation) => aggregation switch
9 | {
10 | TsAggregation.Avg => "AVG",
11 | TsAggregation.Sum => "SUM",
12 | TsAggregation.Min => "MIN",
13 | TsAggregation.Max => "MAX",
14 | TsAggregation.Range => "RANGE",
15 | TsAggregation.Count => "COUNT",
16 | TsAggregation.First => "FIRST",
17 | TsAggregation.Last => "LAST",
18 | TsAggregation.StdP => "STD.P",
19 | TsAggregation.StdS => "STD.S",
20 | TsAggregation.VarP => "VAR.P",
21 | TsAggregation.VarS => "VAR.S",
22 | _ => throw new ArgumentOutOfRangeException(nameof(aggregation), "Invalid aggregation type"),
23 | };
24 |
25 | public static TsAggregation AsAggregation(string aggregation) => aggregation switch
26 | {
27 | "AVG" => TsAggregation.Avg,
28 | "SUM" => TsAggregation.Sum,
29 | "MIN" => TsAggregation.Min,
30 | "MAX" => TsAggregation.Max,
31 | "RANGE" => TsAggregation.Range,
32 | "COUNT" => TsAggregation.Count,
33 | "FIRST" => TsAggregation.First,
34 | "LAST" => TsAggregation.Last,
35 | "STD.P" => TsAggregation.StdP,
36 | "STD.S" => TsAggregation.StdS,
37 | "VAR.P" => TsAggregation.VarP,
38 | "VAR.S" => TsAggregation.VarS,
39 | _ => throw new ArgumentOutOfRangeException(nameof(aggregation), $"Invalid aggregation type '{aggregation}'"),
40 | };
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/CreateExample.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using NRedisTimeSeries.Commands.Enums;
3 | using StackExchange.Redis;
4 | using System.Collections.Generic;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries API for creating new time series.
10 | ///
11 | internal class CreateExample
12 | {
13 | ///
14 | /// Simple time-series creation.
15 | ///
16 | public static void SimpleCreate()
17 | {
18 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
19 | IDatabase db = redis.GetDatabase();
20 | db.TimeSeriesCreate("my_ts");
21 | redis.Close();
22 | }
23 |
24 | ///
25 | /// Examples for creating time-series with parameters.
26 | /// The parameters retentionTime, uncompressed and labels are optional and can be set in any order when used as named argument.
27 | ///
28 | public static void ParameterizedCreate()
29 | {
30 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
31 | IDatabase db = redis.GetDatabase();
32 | db.TimeSeriesCreate("retentionTime_ts", retentionTime: 5000);
33 | db.TimeSeriesCreate("uncompressed_ts", uncompressed: true);
34 | var label = new TimeSeriesLabel("key", "value");
35 | var labels = new List { label };
36 | db.TimeSeriesCreate("labeled_ts", labels: labels);
37 | db.TimeSeriesCreate("parameterized_ts", labels: labels, uncompressed: true, retentionTime: 5000, duplicatePolicy: TsDuplicatePolicy.LAST);
38 | redis.Close();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/InfoQueryIndexExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 |
7 | namespace NRedisTimeSeries.Example
8 | {
9 | ///
10 | /// Examples for NRedisTimeSeries async API for INFO and QUERYINDEX commands.
11 | ///
12 | internal class InfoQueryIndexAsyncExample
13 | {
14 | ///
15 | /// Example for getting the information of a timeseries key with INFO command.
16 | ///
17 | public static async Task InfoAsyncExample()
18 | {
19 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
20 | IDatabase db = redis.GetDatabase();
21 | TimeSeriesInformation info = await db.TimeSeriesInfoAsync("my_ts");
22 | // Now you can access to all the properties of TimeSeriesInformation
23 | Console.WriteLine(info.TotalSamples);
24 | Console.WriteLine((string)info.FirstTimeStamp);
25 | Console.WriteLine((string)info.LastTimeStamp);
26 | redis.Close();
27 | }
28 |
29 | ///
30 | /// Example for using QUERYINDEX.
31 | ///
32 | public static async Task QueryIndexAsyncExample()
33 | {
34 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
35 | IDatabase db = redis.GetDatabase();
36 | var filter = new List { "key=value" };
37 | IReadOnlyList keys = await db.TimeSeriesQueryIndexAsync(filter);
38 | foreach(var key in keys) {
39 | Console.WriteLine(key);
40 | }
41 | redis.Close();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestDataTypes/TestTimeSeriesLabel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.DataTypes;
3 | using Xunit;
4 |
5 | namespace NRedisTimeSeries.Test.TestDataTypes
6 | {
7 | public class TestLabel
8 | {
9 | [Fact]
10 | public void TestLabelConstructor()
11 | {
12 | TimeSeriesLabel label = new TimeSeriesLabel("a", "b");
13 | Assert.Equal("a", label.Key);
14 | Assert.Equal("b", label.Value);
15 | }
16 |
17 |
18 | [Fact]
19 | public void TestLbaelEquals()
20 | {
21 | TimeSeriesLabel label_ab = new TimeSeriesLabel("a", "b");
22 | TimeSeriesLabel label1 = new TimeSeriesLabel("a", "b");
23 | TimeSeriesLabel label2 = new TimeSeriesLabel("a", "c");
24 | TimeSeriesLabel label3 = new TimeSeriesLabel("c", "b");
25 |
26 | Assert.Equal(label_ab, label1);
27 | Assert.NotEqual(label_ab, label2);
28 | Assert.NotEqual(label_ab, label3);
29 | }
30 |
31 | [Fact]
32 | public void TestLabelHashCode()
33 | {
34 | TimeSeriesLabel label_ab = new TimeSeriesLabel("a", "b");
35 | TimeSeriesLabel label1 = new TimeSeriesLabel("a", "b");
36 | TimeSeriesLabel label2 = new TimeSeriesLabel("a", "c");
37 | TimeSeriesLabel label3 = new TimeSeriesLabel("c", "b");
38 |
39 | Assert.Equal(label_ab.GetHashCode(), label1.GetHashCode());
40 | Assert.NotEqual(label_ab.GetHashCode(), label2.GetHashCode());
41 | Assert.NotEqual(label_ab.GetHashCode(), label3.GetHashCode());
42 | }
43 |
44 | [Fact]
45 | public void TestLabelToString()
46 | {
47 | TimeSeriesLabel label = new TimeSeriesLabel("a", "b");
48 | Assert.Equal("Key: a, Val:b", (string)label);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/CreateExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using NRedisTimeSeries.Commands.Enums;
3 | using StackExchange.Redis;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 |
7 | namespace NRedisTimeSeries.Example
8 | {
9 | ///
10 | /// Examples for NRedisTimeSeries async API for creating new time series.
11 | ///
12 | internal class CreateAsyncExample
13 | {
14 | ///
15 | /// Simple time-series creation.
16 | ///
17 | public static async Task SimpleCreateAsync()
18 | {
19 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
20 | IDatabase db = redis.GetDatabase();
21 | await db.TimeSeriesCreateAsync("my_ts");
22 | redis.Close();
23 | }
24 |
25 | ///
26 | /// Examples for creating time-series with parameters.
27 | /// The parameters retentionTime, uncompressed and labels are optional and can be set in any order when used as named argument.
28 | ///
29 | public static async Task ParameterizedCreateAsync()
30 | {
31 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
32 | IDatabase db = redis.GetDatabase();
33 | await db.TimeSeriesCreateAsync("retentionTime_ts", retentionTime: 5000);
34 | await db.TimeSeriesCreateAsync("uncompressed_ts", uncompressed: true);
35 | var label = new TimeSeriesLabel("key", "value");
36 | var labels = new List { label };
37 | await db.TimeSeriesCreateAsync("labeled_ts", labels: labels);
38 | await db.TimeSeriesCreateAsync("parameterized_ts", labels: labels, uncompressed: true, retentionTime: 5000, duplicatePolicy: TsDuplicatePolicy.LAST);
39 | redis.Close();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestDel.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System;
4 | using System.Collections.Generic;
5 | using Xunit;
6 |
7 |
8 | namespace NRedisTimeSeries.Test.TestAPI
9 | {
10 | public class TestDel : AbstractTimeSeriesTest, IDisposable
11 | {
12 | private readonly string key = "DEL_TESTS";
13 |
14 | public TestDel(RedisFixture redisFixture) : base(redisFixture) { }
15 |
16 | public void Dispose()
17 | {
18 | redisFixture.Redis.GetDatabase().KeyDelete(key);
19 | }
20 |
21 | private List CreateData(IDatabase db, int timeBucket)
22 | {
23 | var tuples = new List();
24 | for (int i = 0; i < 10; i++)
25 | {
26 | TimeStamp ts = db.TimeSeriesAdd(key, i*timeBucket, i);
27 | tuples.Add(new TimeSeriesTuple(ts, i));
28 | }
29 | return tuples;
30 | }
31 |
32 | [Fact]
33 | public void TestDelNotExists()
34 | {
35 | IDatabase db = redisFixture.Redis.GetDatabase();
36 | var ex = Assert.Throws(() => db.TimeSeriesDel(key, "-", "+"));
37 | Assert.Equal("ERR TSDB: the key does not exist", ex.Message);
38 | }
39 |
40 | [Fact]
41 | public void TestDelRange()
42 | {
43 | IDatabase db = redisFixture.Redis.GetDatabase();
44 | var tuples = CreateData(db, 50);
45 | TimeStamp from = tuples[0].Time;
46 | TimeStamp to = tuples[5].Time;
47 | Assert.Equal(6, db.TimeSeriesDel(key, from, to));
48 |
49 | // check that the operation deleted the timestamps
50 | IReadOnlyList res = db.TimeSeriesRange(key, from, to);
51 | Assert.Equal(0, res.Count);
52 | Assert.NotNull(db.TimeSeriesGet(key));
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestDelAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestAPI
8 | {
9 | public class TestDelAsync : AbstractTimeSeriesTest
10 | {
11 | public TestDelAsync(RedisFixture redisFixture) : base(redisFixture) { }
12 |
13 | private async Task> CreateData(IDatabase db, string key, int timeBucket)
14 | {
15 | var tuples = new List();
16 | for (var i = 0; i < 10; i++)
17 | {
18 | var ts = await db.TimeSeriesAddAsync(key, i * timeBucket, i);
19 | tuples.Add(new TimeSeriesTuple(ts, i));
20 | }
21 | return tuples;
22 | }
23 |
24 | [Fact]
25 | public async Task TestDelNotExists()
26 | {
27 | var key = CreateKeyName();
28 | IDatabase db = redisFixture.Redis.GetDatabase();
29 | var ex = await Assert.ThrowsAsync(async () => await db.TimeSeriesDelAsync(key, "-", "+"));
30 | Assert.Equal("ERR TSDB: the key does not exist", ex.Message);
31 | }
32 |
33 | [Fact]
34 | public async Task TestDelRange()
35 | {
36 | IDatabase db = redisFixture.Redis.GetDatabase();
37 | var key = CreateKeyName();
38 | var tuples = await CreateData(db, key, 50);
39 | TimeStamp from = tuples[0].Time;
40 | TimeStamp to = tuples[5].Time;
41 | Assert.Equal(6, await db.TimeSeriesDelAsync(key, from, to));
42 |
43 | // check that the operation deleted the timestamps
44 | IReadOnlyList res = await db.TimeSeriesRangeAsync(key, from, to);
45 | Assert.Equal(0, res.Count);
46 | Assert.NotNull(await db.TimeSeriesGetAsync(key));
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/AbstractTimeSeriesTest.cs:
--------------------------------------------------------------------------------
1 | using StackExchange.Redis;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Runtime.CompilerServices;
6 | using System.Threading.Tasks;
7 | using NRedisTimeSeries.DataTypes;
8 | using Xunit;
9 |
10 | namespace NRedisTimeSeries.Test.TestAPI
11 | {
12 | public abstract class AbstractTimeSeriesTest : IClassFixture, IAsyncLifetime
13 | {
14 | protected internal RedisFixture redisFixture;
15 |
16 | protected internal AbstractTimeSeriesTest(RedisFixture redisFixture) => this.redisFixture = redisFixture;
17 |
18 | private List keyNames = new List();
19 |
20 | protected internal string CreateKeyName([CallerMemberName] string memberName = "") => CreateKeyNames(1, memberName)[0];
21 |
22 | protected internal string[] CreateKeyNames(int count, [CallerMemberName] string memberName = "")
23 | {
24 | if (count < 1) throw new ArgumentOutOfRangeException(nameof(count), "Must be greater than zero.");
25 |
26 | var newKeys = new string[count];
27 | for (var i = 0; i < count; i++)
28 | {
29 | newKeys[i] = $"{GetType().Name}:{memberName}:{i}";
30 | }
31 |
32 | keyNames.AddRange(newKeys);
33 |
34 | return newKeys;
35 | }
36 |
37 | protected internal static List ReverseData(List data)
38 | {
39 | var tuples = new List(data.Count);
40 | for (var i = data.Count - 1; i >= 0; i--)
41 | {
42 | tuples.Add(data[i]);
43 | }
44 |
45 | return tuples;
46 | }
47 |
48 | public Task InitializeAsync() => Task.CompletedTask;
49 |
50 | public async Task DisposeAsync()
51 | {
52 | var redis = redisFixture.Redis.GetDatabase();
53 | await redis.KeyDeleteAsync(keyNames.Select(i => (RedisKey)i).ToArray());
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/DataTypes/TimeSeriesLabel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace NRedisTimeSeries.DataTypes
4 | {
5 | ///
6 | /// A key-value pair class represetns metadata label of time-series.
7 | ///
8 | public class TimeSeriesLabel
9 | {
10 | ///
11 | /// Label key
12 | ///
13 | public string Key { get; }
14 |
15 | ///
16 | /// Label value
17 | ///
18 | public string Value { get; }
19 |
20 | ///
21 | /// Create a new TimeSeriesLabel out of key and value strings.
22 | ///
23 | /// Key string
24 | /// Value string
25 | public TimeSeriesLabel(string key, string value) => (Key, Value) = (key, value);
26 |
27 | ///
28 | /// Equality of TimeSeriesLabel objects
29 | ///
30 | /// Object to compare
31 | /// If two TimeSeriesLabel objects are equal
32 | public override bool Equals(object obj) =>
33 | obj is TimeSeriesLabel label &&
34 | Key == label.Key &&
35 | Value == label.Value;
36 |
37 | ///
38 | /// Implicit cast from TimeSeriesLabel to string.
39 | ///
40 | /// TimeSeriesLabel
41 | public static implicit operator string(TimeSeriesLabel tsl) => string.Format("Key: {0}, Val:{1}", tsl.Key, tsl.Value);
42 |
43 | ///
44 | /// TimeSeriesLabel object hash code.
45 | ///
46 | /// TimeSeriesLabel object hash code.
47 | public override int GetHashCode()
48 | {
49 | var hashCode = 206514262;
50 | hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Key);
51 | hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Value);
52 | return hashCode;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/DataTypes/TimeSeriesTuple.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace NRedisTimeSeries.DataTypes
4 | {
5 | ///
6 | /// A class represents time-series timestamp-value pair
7 | ///
8 | public class TimeSeriesTuple
9 | {
10 | ///
11 | /// Tuple key - timestamp.
12 | ///
13 | public TimeStamp Time { get; }
14 |
15 | ///
16 | /// Tuple value
17 | ///
18 | public double Val { get; }
19 |
20 | ///
21 | /// Create new TimeSeriesTuple.
22 | ///
23 | /// Timestamp
24 | /// Value
25 | public TimeSeriesTuple(TimeStamp time, double val) => (Time, Val) = (time, val);
26 |
27 | ///
28 | /// Equality of TimeSeriesTuple objects
29 | ///
30 | /// Object to compare
31 | /// If two TimeSeriesTuple objects are equal
32 | public override bool Equals(object obj) =>
33 | obj is TimeSeriesTuple tuple &&
34 | EqualityComparer.Default.Equals(Time, tuple.Time) &&
35 | Val == tuple.Val;
36 |
37 | ///
38 | /// Implicit cast from TimeSeriesTuple to string.
39 | ///
40 | /// TimeSeriesTuple
41 | public static implicit operator string(TimeSeriesTuple tst) =>
42 | string.Format("Time: {0}, Val:{1}", (string)tst.Time, tst.Val);
43 |
44 | ///
45 | /// TimeSeriesTuple object hash code.
46 | ///
47 | /// TimeSeriesTuple object hash code.
48 | public override int GetHashCode()
49 | {
50 | var hashCode = 459537088;
51 | hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(Time);
52 | hashCode = (hashCode * -1521134295) + Val.GetHashCode();
53 | return hashCode;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/Commands/Enums/Aggregation.cs:
--------------------------------------------------------------------------------
1 | namespace NRedisTimeSeries.Commands.Enums
2 | {
3 | ///
4 | /// An aggregation type to be used with a time bucket.
5 | ///
6 | public enum TsAggregation
7 | {
8 | ///
9 | /// The average of all samples in the aggregation
10 | ///
11 | Avg,
12 |
13 | ///
14 | /// A sum of all samples in the aggregation
15 | ///
16 | Sum,
17 |
18 | ///
19 | /// A minimum sample of all samples in the aggregation
20 | ///
21 | Min,
22 |
23 | ///
24 | /// A maximum sample of all samples in the aggregation
25 | ///
26 | Max,
27 |
28 | ///
29 | /// A range of the min and max sample of all samples in the aggregation (range r = max-min)
30 | /// For example if the min sample was 100 and the max was 400, the range aggregation would return 300
31 | ///
32 | Range,
33 |
34 | ///
35 | /// The total number of all samples in the aggregation
36 | ///
37 | Count,
38 |
39 | ///
40 | /// The first sample in the aggregation
41 | ///
42 | First,
43 |
44 | ///
45 | /// The last sample in the aggregation
46 | ///
47 | Last,
48 |
49 | ///
50 | /// The standard deviation based on the entire population
51 | /// The standard deviation is a measure of how widely values are dispersed from the average sample in the aggregation
52 | ///
53 | StdP,
54 |
55 | ///
56 | /// The standard deviation based on a sample of the population
57 | /// The standard deviation is a measure of how widely values are dispersed from the average sample in the aggregation
58 | ///
59 | StdS,
60 |
61 | ///
62 | /// The variance based on the entire population
63 | /// The variance is the average of the squared differences from the mean
64 | ///
65 | VarP,
66 |
67 | ///
68 | /// The variance based on a sample of the population
69 | /// The variance is the average of the squared differences from the mean
70 | ///
71 | VarS,
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/MGetExample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries API for MGET queries.
10 | ///
11 | internal class MGetExample
12 | {
13 | ///
14 | /// Example for basic usage of RedisTimeSeries MGET command with a filter.
15 | /// The NRedisTimeSeries SimpleMGetExample returns and IReadOnlyList<(string key, IReadOnlyList labels, TimeSeriesTuple value)> collection.
16 | ///
17 | public static void SimpleMGetExample()
18 | {
19 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
20 | IDatabase db = redis.GetDatabase();
21 | var filter = new List { "key=value" };
22 | var results = db.TimeSeriesMGet(filter);
23 | // Values extraction example. No lables in this case.
24 | foreach (var result in results)
25 | {
26 | Console.WriteLine(result.key);
27 | TimeSeriesTuple value = result.value;
28 | Console.WriteLine(value);
29 | }
30 | redis.Close();
31 | }
32 |
33 | ///
34 | /// Example for basic usage of RedisTimeSeries MGET command with a filter and WITHLABELS flag.
35 | /// The NRedisTimeSeries SimpleMGetExample returns and IReadOnlyList<(string key, IReadOnlyList labels, TimeSeriesTuple value)> collection.
36 | ///
37 | public static void MGetWithLabelsExample()
38 | {
39 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
40 | IDatabase db = redis.GetDatabase();
41 | var filter = new List { "key=value" };
42 | var results = db.TimeSeriesMGet(filter, withLabels: true);
43 | // Values extraction example.
44 | foreach (var result in results)
45 | {
46 | Console.WriteLine(result.key);
47 | IReadOnlyList labels = result.labels;
48 | foreach(TimeSeriesLabel label in labels){
49 | Console.WriteLine(label);
50 | }
51 | TimeSeriesTuple value = result.value;
52 | Console.WriteLine(value);
53 | }
54 | redis.Close();
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestDataTypes/TestTimeSeriesRule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NRedisTimeSeries.Commands;
3 | using NRedisTimeSeries.Commands.Enums;
4 | using NRedisTimeSeries.DataTypes;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestDataTypes
8 | {
9 | public class TestTimeSeriesRule
10 | {
11 | public TestTimeSeriesRule() { }
12 |
13 | [Fact]
14 | public void TestRuleConstructor()
15 | {
16 | TimeSeriesRule rule = new TimeSeriesRule("key", 50, TsAggregation.Avg);
17 | Assert.Equal("key", rule.DestKey);
18 | Assert.Equal(TsAggregation.Avg, rule.Aggregation);
19 | Assert.Equal(50, rule.TimeBucket);
20 | }
21 |
22 | [Fact]
23 | public void TestRuleEquals()
24 | {
25 | TimeSeriesRule rule = new TimeSeriesRule("key", 50, TsAggregation.Avg);
26 |
27 | TimeSeriesRule rule1 = new TimeSeriesRule("key", 50, TsAggregation.Avg);
28 | TimeSeriesRule rule2 = new TimeSeriesRule("key2", 50, TsAggregation.Avg);
29 | TimeSeriesRule rule3 = new TimeSeriesRule("key", 51, TsAggregation.Avg);
30 | TimeSeriesRule rule4 = new TimeSeriesRule("key", 50, TsAggregation.Count);
31 |
32 | Assert.Equal(rule, rule1);
33 | Assert.NotEqual(rule, rule2);
34 | Assert.NotEqual(rule, rule3);
35 | Assert.NotEqual(rule, rule4);
36 | }
37 |
38 | [Fact]
39 | public void TestRuleHashCode()
40 | {
41 | TimeSeriesRule rule = new TimeSeriesRule("key", 50, TsAggregation.Avg);
42 |
43 | TimeSeriesRule rule1 = new TimeSeriesRule("key", 50, TsAggregation.Avg);
44 | TimeSeriesRule rule2 = new TimeSeriesRule("key2", 50, TsAggregation.Avg);
45 | TimeSeriesRule rule3 = new TimeSeriesRule("key", 51, TsAggregation.Avg);
46 | TimeSeriesRule rule4 = new TimeSeriesRule("key", 50, TsAggregation.Count);
47 |
48 | Assert.Equal(rule.GetHashCode(), rule1.GetHashCode());
49 | Assert.NotEqual(rule.GetHashCode(), rule2.GetHashCode());
50 | Assert.NotEqual(rule.GetHashCode(), rule3.GetHashCode());
51 | Assert.NotEqual(rule.GetHashCode(), rule4.GetHashCode());
52 | }
53 |
54 | [Fact]
55 | public void TestRuleToString()
56 | {
57 | TimeSeriesRule rule = new TimeSeriesRule("key", 50, TsAggregation.Avg);
58 | Assert.Equal("DestinationKey: key, TimeBucket: 50, Aggregation: AVG", (string)rule);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/MGetExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 |
7 | namespace NRedisTimeSeries.Example
8 | {
9 | ///
10 | /// Examples for NRedisTimeSeries async API for MGET queries.
11 | ///
12 | internal class MGetAsyncExample
13 | {
14 | ///
15 | /// Example for basic usage of RedisTimeSeries MGET command with a filter.
16 | /// The NRedisTimeSeries SimpleMGetExample returns and IReadOnlyList<(string key, IReadOnlyList labels, TimeSeriesTuple value)> collection.
17 | ///
18 | public static async Task SimpleMGetAsyncExample()
19 | {
20 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
21 | IDatabase db = redis.GetDatabase();
22 | var filter = new List { "key=value" };
23 | var results = await db.TimeSeriesMGetAsync(filter);
24 | // Values extraction example. No lables in this case.
25 | foreach (var result in results)
26 | {
27 | Console.WriteLine(result.key);
28 | TimeSeriesTuple value = result.value;
29 | Console.WriteLine(value);
30 | }
31 | redis.Close();
32 | }
33 |
34 | ///
35 | /// Example for basic usage of RedisTimeSeries MGET command with a filter and WITHLABELS flag.
36 | /// The NRedisTimeSeries SimpleMGetExample returns and IReadOnlyList<(string key, IReadOnlyList labels, TimeSeriesTuple value)> collection.
37 | ///
38 | public static async Task MGetWithLabelsAsyncExample()
39 | {
40 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
41 | IDatabase db = redis.GetDatabase();
42 | var filter = new List { "key=value" };
43 | var results = await db.TimeSeriesMGetAsync(filter, withLabels: true);
44 | // Values extraction example.
45 | foreach (var result in results)
46 | {
47 | Console.WriteLine(result.key);
48 | IReadOnlyList labels = result.labels;
49 | foreach(TimeSeriesLabel label in labels){
50 | Console.WriteLine(label);
51 | }
52 | TimeSeriesTuple value = result.value;
53 | Console.WriteLine(value);
54 | }
55 | redis.Close();
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/DataTypes/TimeSeriesRule.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.Commands.Enums;
2 | using NRedisTimeSeries.Extensions;
3 | using System.Collections.Generic;
4 |
5 | namespace NRedisTimeSeries.DataTypes
6 | {
7 | ///
8 | /// A class that represents time-series aggregation rule.
9 | ///
10 | public class TimeSeriesRule
11 | {
12 | ///
13 | /// Rule's destination key.
14 | ///
15 | public string DestKey { get; private set; }
16 |
17 | ///
18 | /// Rule's aggregation time bucket.
19 | ///
20 | public long TimeBucket { get; private set; }
21 |
22 | ///
23 | /// Rule's aggregation type.
24 | ///
25 | public TsAggregation Aggregation { get; private set; }
26 |
27 | ///
28 | /// Builds a time-series aggregation rule
29 | ///
30 | /// Rule's destination key.
31 | /// Rule's aggregation time bucket.
32 | /// Rule's aggregation type.
33 | public TimeSeriesRule(string destKey, long timeBucket, TsAggregation aggregation) =>
34 | (DestKey, TimeBucket, Aggregation) = (destKey, timeBucket, aggregation);
35 |
36 | ///
37 | /// Equality of TimeSeriesRule objects
38 | ///
39 | /// Object to compare
40 | /// If two TimeSeriesRule objects are equal
41 | public override bool Equals(object obj) =>
42 | obj is TimeSeriesRule rule &&
43 | DestKey == rule.DestKey &&
44 | TimeBucket == rule.TimeBucket &&
45 | Aggregation == rule.Aggregation;
46 |
47 | ///
48 | /// Implicit cast from TimeSeriesRule to string.
49 | ///
50 | /// TimeSeriesRule
51 | public static implicit operator string(TimeSeriesRule tsr) =>
52 | string.Format("DestinationKey: {0}, TimeBucket: {1}, Aggregation: {2}", tsr.DestKey, tsr.TimeBucket, tsr.Aggregation.AsArg());
53 |
54 | ///
55 | /// TimeSeriesRule object hash code.
56 | ///
57 | /// TimeSeriesRule object hash code.
58 | public override int GetHashCode()
59 | {
60 | var hashCode = 1554951643;
61 | hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(DestKey);
62 | hashCode = (hashCode * -1521134295) + TimeBucket.GetHashCode();
63 | hashCode = (hashCode * -1521134295) + ((int)Aggregation).GetHashCode();
64 | return hashCode;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestMGetAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Xunit;
5 |
6 | namespace NRedisTimeSeries.Test.TestAPI
7 | {
8 | public class TestMGetAsync : AbstractTimeSeriesTest
9 | {
10 | public TestMGetAsync(RedisFixture redisFixture) : base(redisFixture) { }
11 |
12 | [Fact]
13 | public async Task TestMGetQuery()
14 | {
15 | var keys = CreateKeyNames(2);
16 | var db = redisFixture.Redis.GetDatabase();
17 |
18 | var label1 = new TimeSeriesLabel(keys[0], "value");
19 | var label2 = new TimeSeriesLabel(keys[1], "value2");
20 | var labels1 = new List { label1, label2 };
21 | var labels2 = new List { label1 };
22 |
23 | var ts1 = await db.TimeSeriesAddAsync(keys[0], "*", 1.1, labels: labels1);
24 | var tuple1 = new TimeSeriesTuple(ts1, 1.1);
25 | var ts2 = await db.TimeSeriesAddAsync(keys[1], "*", 2.2, labels: labels2);
26 | var tuple2 = new TimeSeriesTuple(ts2, 2.2);
27 |
28 | var results = await db.TimeSeriesMGetAsync(new List { $"{keys[0]}=value" });
29 | Assert.Equal(2, results.Count);
30 | Assert.Equal(keys[0], results[0].key);
31 | Assert.Equal(tuple1, results[0].value);
32 | Assert.Equal(new List(), results[0].labels);
33 | Assert.Equal(keys[1], results[1].key);
34 | Assert.Equal(tuple2, results[1].value);
35 | Assert.Equal(new List(), results[1].labels);
36 | }
37 |
38 | [Fact]
39 | public async Task TestMGetQueryWithLabels()
40 | {
41 | var keys = CreateKeyNames(2);
42 | var db = redisFixture.Redis.GetDatabase();
43 |
44 | var label1 = new TimeSeriesLabel(keys[0], "value");
45 | var label2 = new TimeSeriesLabel(keys[1], "value2");
46 | var labels1 = new List { label1, label2 };
47 | var labels2 = new List { label1 };
48 |
49 | var ts1 = await db.TimeSeriesAddAsync(keys[0], "*", 1.1, labels: labels1);
50 | var tuple1 = new TimeSeriesTuple(ts1, 1.1);
51 | var ts2 = await db.TimeSeriesAddAsync(keys[1], "*", 2.2, labels: labels2);
52 | var tuple2 = new TimeSeriesTuple(ts2, 2.2);
53 |
54 | var results = await db.TimeSeriesMGetAsync(new List { $"{keys[0]}=value" }, withLabels: true);
55 | Assert.Equal(2, results.Count);
56 | Assert.Equal(keys[0], results[0].key);
57 | Assert.Equal(tuple1, results[0].value);
58 | Assert.Equal(labels1, results[0].labels);
59 | Assert.Equal(keys[1], results[1].key);
60 | Assert.Equal(tuple2, results[1].value);
61 | Assert.Equal(labels2, results[1].labels);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/IncrByExample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries API for INCRBY.
10 | ///
11 | internal class IncrByExample
12 | {
13 | ///
14 | /// Example for increasing the value of the last sample by 5.
15 | ///
16 | public static void DefaultIncrByExample()
17 | {
18 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
19 | IDatabase db = redis.GetDatabase();
20 | db.TimeSeriesIncrBy("my_ts", 5);
21 | redis.Close();
22 | }
23 |
24 | ///
25 | /// Example for setting the last sample timestamp to system time and its value to 5, with INCRBY.
26 | ///
27 | public static void SystemTimeIncrByExample()
28 | {
29 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
30 | IDatabase db = redis.GetDatabase();
31 | db.TimeSeriesIncrBy("my_ts", 5, timestamp: "*");
32 | redis.Close();
33 | }
34 |
35 | ///
36 | /// Example for setting the last sample timestamp to DateTime.UtcNow and its value to 5, with INCRBY.
37 | ///
38 | public static void DateTimeIncrByExample()
39 | {
40 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
41 | IDatabase db = redis.GetDatabase();
42 | db.TimeSeriesIncrBy("my_ts", 5, timestamp: DateTime.UtcNow);
43 | redis.Close();
44 | }
45 |
46 | ///
47 | /// Example for setting the last sample timestamp to long value and its value to 5, with INCRBY.
48 | ///
49 | public static void LongIncrByExample()
50 | {
51 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
52 | IDatabase db = redis.GetDatabase();
53 | db.TimeSeriesIncrBy("my_ts", 5, timestamp: long.MaxValue);
54 | redis.Close();
55 | }
56 |
57 | ///
58 | /// Example for setting the last sample timestamp to system time and its value to 5, with INCRBY.
59 | /// The parameters retentionTime, uncompressed and labels are optional and can be set in any order when used as named argument.
60 | ///
61 | public static void ParameterizedIncrByExample()
62 | {
63 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
64 | IDatabase db = redis.GetDatabase();
65 | var label = new TimeSeriesLabel("key", "value");
66 | var labels = new List { label };
67 | db.TimeSeriesIncrBy("my_ts", 5, timestamp: "*", retentionTime:5000, uncompressed:true, labels: labels);
68 | redis.Close();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/DecrByExample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 |
6 | namespace NRedisTimeSeries.Example
7 | {
8 | ///
9 | /// Examples for NRedisTimeSeries API for DECRBY.
10 | ///
11 | internal class DecrByExample
12 | {
13 | ///
14 | /// Example for decreasing the value of the last sample by 5.
15 | ///
16 | public static void DefaultDecrByExample()
17 | {
18 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
19 | IDatabase db = redis.GetDatabase();
20 | db.TimeSeriesDecrBy("my_ts", 5);
21 | redis.Close();
22 | }
23 |
24 | ///
25 | /// Example for setting the last sample timestamp to system time and its value to -5, with DECRBY.
26 | ///
27 | public static void SystemTimeDecrByExample()
28 | {
29 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
30 | IDatabase db = redis.GetDatabase();
31 | db.TimeSeriesDecrBy("my_ts", 5, timestamp: "*");
32 | redis.Close();
33 | }
34 |
35 | ///
36 | /// Example for setting the last sample timestamp to DateTime.UtcNow and its value to -5, with DECRBY.
37 | ///
38 | public static void DateTimeDecrByExample()
39 | {
40 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
41 | IDatabase db = redis.GetDatabase();
42 | db.TimeSeriesDecrBy("my_ts", 5, timestamp: DateTime.UtcNow);
43 | redis.Close();
44 | }
45 |
46 | ///
47 | /// Example for setting the last sample timestamp to long value and its value to -5, with DECRBY.
48 | ///
49 | public static void LongDecrByExample()
50 | {
51 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
52 | IDatabase db = redis.GetDatabase();
53 | db.TimeSeriesDecrBy("my_ts", 5, timestamp: long.MaxValue);
54 | redis.Close();
55 | }
56 |
57 | ///
58 | /// Example for setting the last sample timestamp to system time and its value to -5, with DECRBY.
59 | /// The parameters retentionTime, uncompressed and labels are optional and can be set in any order when used as named argument.
60 | ///
61 | public static void ParameterizedDecrByExample()
62 | {
63 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
64 | IDatabase db = redis.GetDatabase();
65 | var label = new TimeSeriesLabel("key", "value");
66 | var labels = new List { label };
67 | db.TimeSeriesDecrBy("my_ts", 5, timestamp: "*", retentionTime: 5000, uncompressed: true, labels: labels);
68 | redis.Close();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/IncrByExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 |
7 | namespace NRedisTimeSeries.Example
8 | {
9 | ///
10 | /// Examples for NRedisTimeSeries async API for INCRBY.
11 | ///
12 | internal class IncrByAsyncExample
13 | {
14 | ///
15 | /// Example for increasing the value of the last sample by 5.
16 | ///
17 | public static async Task DefaultIncrByAsyncExample()
18 | {
19 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
20 | IDatabase db = redis.GetDatabase();
21 | await db.TimeSeriesIncrByAsync("my_ts", 5);
22 | redis.Close();
23 | }
24 |
25 | ///
26 | /// Example for setting the last sample timestamp to system time and its value to 5, with INCRBY.
27 | ///
28 | public static async Task SystemTimeIncrByAsyncExample()
29 | {
30 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
31 | IDatabase db = redis.GetDatabase();
32 | await db.TimeSeriesIncrByAsync("my_ts", 5, timestamp: "*");
33 | redis.Close();
34 | }
35 |
36 | ///
37 | /// Example for setting the last sample timestamp to DateTime.UtcNow and its value to 5, with INCRBY.
38 | ///
39 | public static async Task DateTimeIncrByAsyncExample()
40 | {
41 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
42 | IDatabase db = redis.GetDatabase();
43 | await db.TimeSeriesIncrByAsync("my_ts", 5, timestamp: DateTime.UtcNow);
44 | redis.Close();
45 | }
46 |
47 | ///
48 | /// Example for setting the last sample timestamp to long value and its value to 5, with INCRBY.
49 | ///
50 | public static async Task LongIncrByAsyncExample()
51 | {
52 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
53 | IDatabase db = redis.GetDatabase();
54 | await db.TimeSeriesIncrByAsync("my_ts", 5, timestamp: long.MaxValue);
55 | redis.Close();
56 | }
57 |
58 | ///
59 | /// Example for setting the last sample timestamp to system time and its value to 5, with INCRBY.
60 | /// The parameters retentionTime, uncompressed and labels are optional and can be set in any order when used as named argument.
61 | ///
62 | public static async Task ParameterizedIncrByAsyncExample()
63 | {
64 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
65 | IDatabase db = redis.GetDatabase();
66 | var label = new TimeSeriesLabel("key", "value");
67 | var labels = new List { label };
68 | await db.TimeSeriesIncrByAsync("my_ts", 5, timestamp: "*", retentionTime: 5000, uncompressed: true, labels: labels);
69 | redis.Close();
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/DecrByExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using NRedisTimeSeries.DataTypes;
5 | using StackExchange.Redis;
6 |
7 | namespace NRedisTimeSeries.Example
8 | {
9 | ///
10 | /// Examples for NRedisTimeSeries async API for DECRBY.
11 | ///
12 | internal class DecrByAsyncExample
13 | {
14 | ///
15 | /// Example for decreasing the value of the last sample by 5.
16 | ///
17 | public static async Task DefaultDecrByAsyncExample()
18 | {
19 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
20 | IDatabase db = redis.GetDatabase();
21 | await db.TimeSeriesDecrByAsync("my_ts", 5);
22 | redis.Close();
23 | }
24 |
25 | ///
26 | /// Example for setting the last sample timestamp to system time and its value to -5, with DECRBY.
27 | ///
28 | public static async Task SystemTimeDecrByAsyncExample()
29 | {
30 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
31 | IDatabase db = redis.GetDatabase();
32 | await db.TimeSeriesDecrByAsync("my_ts", 5, timestamp: "*");
33 | redis.Close();
34 | }
35 |
36 | ///
37 | /// Example for setting the last sample timestamp to DateTime.UtcNow and its value to -5, with DECRBY.
38 | ///
39 | public static async Task DateTimeDecrByAsyncExample()
40 | {
41 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
42 | IDatabase db = redis.GetDatabase();
43 | await db.TimeSeriesDecrByAsync("my_ts", 5, timestamp: DateTime.UtcNow);
44 | redis.Close();
45 | }
46 |
47 | ///
48 | /// Example for setting the last sample timestamp to long value and its value to -5, with DECRBY.
49 | ///
50 | public static async Task LongDecrByAsyncExample()
51 | {
52 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
53 | IDatabase db = redis.GetDatabase();
54 | await db.TimeSeriesDecrByAsync("my_ts", 5, timestamp: long.MaxValue);
55 | redis.Close();
56 | }
57 |
58 | ///
59 | /// Example for setting the last sample timestamp to system time and its value to -5, with DECRBY.
60 | /// The parameters retentionTime, uncompressed and labels are optional and can be set in any order when used as named argument.
61 | ///
62 | public static async Task ParameterizedDecrByAsyncExample()
63 | {
64 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
65 | IDatabase db = redis.GetDatabase();
66 | var label = new TimeSeriesLabel("key", "value");
67 | var labels = new List { label };
68 | await db.TimeSeriesDecrByAsync("my_ts", 5, timestamp: "*", retentionTime: 5000, uncompressed: true, labels: labels);
69 | redis.Close();
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestMGet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestAPI
8 | {
9 | public class TestMGet : AbstractTimeSeriesTest, IDisposable
10 | {
11 |
12 | private readonly string[] keys = { "MGET_TESTS_1", "MGET_TESTS_2" };
13 |
14 | public TestMGet(RedisFixture redisFixture) : base(redisFixture) { }
15 |
16 | public void Dispose()
17 | {
18 | foreach (string key in keys)
19 | {
20 | redisFixture.Redis.GetDatabase().KeyDelete(key);
21 | }
22 | }
23 |
24 | [Fact]
25 | public void TestMGetQuery()
26 | {
27 | IDatabase db = redisFixture.Redis.GetDatabase();
28 |
29 | var label1 = new TimeSeriesLabel("MGET_TESTS_1", "value");
30 | var label2 = new TimeSeriesLabel("MGET_TESTS_2", "value2");
31 | var labels1 = new List { label1, label2 };
32 | var labels2 = new List { label1 };
33 |
34 | TimeStamp ts1 = db.TimeSeriesAdd(keys[0], "*", 1.1, labels: labels1);
35 | TimeSeriesTuple tuple1 = new TimeSeriesTuple(ts1, 1.1);
36 | TimeStamp ts2 = db.TimeSeriesAdd(keys[1], "*", 2.2, labels: labels2);
37 | TimeSeriesTuple tuple2 = new TimeSeriesTuple(ts2, 2.2);
38 | var results = db.TimeSeriesMGet(new List { "MGET_TESTS_1=value" });
39 | Assert.Equal(2, results.Count);
40 | Assert.Equal(keys[0], results[0].key);
41 | Assert.Equal( tuple1 , results[0].value);
42 | Assert.Equal(new List(), results[0].labels);
43 | Assert.Equal(keys[1], results[1].key);
44 | Assert.Equal(tuple2 , results[1].value);
45 | Assert.Equal(new List(), results[1].labels);
46 |
47 | }
48 |
49 | [Fact]
50 | public void TestMGetQueryWithLabels()
51 | {
52 | IDatabase db = redisFixture.Redis.GetDatabase();
53 |
54 | var label1 = new TimeSeriesLabel("MGET_TESTS_1", "value");
55 | var label2 = new TimeSeriesLabel("MGET_TESTS_2", "value2");
56 | var labels1 = new List { label1, label2 };
57 | var labels2 = new List { label1 };
58 |
59 | TimeStamp ts1 = db.TimeSeriesAdd(keys[0], "*", 1.1, labels: labels1);
60 | TimeSeriesTuple tuple1 = new TimeSeriesTuple(ts1, 1.1);
61 | TimeStamp ts2 = db.TimeSeriesAdd(keys[1], "*", 2.2, labels: labels2);
62 | TimeSeriesTuple tuple2 = new TimeSeriesTuple(ts2, 2.2);
63 |
64 | var results = db.TimeSeriesMGet(new List { "MGET_TESTS_1=value" }, withLabels: true);
65 | Assert.Equal(2, results.Count);
66 | Assert.Equal(keys[0], results[0].key);
67 | Assert.Equal(tuple1, results[0].value);
68 | Assert.Equal(labels1, results[0].labels);
69 | Assert.Equal(keys[1], results[1].key);
70 | Assert.Equal(tuple2 , results[1].value);
71 | Assert.Equal(labels2, results[1].labels);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/AddExample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using NRedisTimeSeries.Commands.Enums;
5 | using StackExchange.Redis;
6 |
7 | namespace NRedisTimeSeries.Example
8 | {
9 | ///
10 | /// Examples for NRedisTimeSeries API for adding new sample to time series.
11 | ///
12 | internal class AddExample
13 | {
14 | ///
15 | /// Example for using RedisTimeSeries default "*" charecter for system time.
16 | /// The TimeSeriesAdd method gets a TimeStamp type parameter, which in this case the string "*"
17 | /// is implicitly casted into a new TimeStamp object.
18 | ///
19 | public static void DefaultAdd()
20 | {
21 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
22 | IDatabase db = redis.GetDatabase();
23 | TimeStamp timestamp = "*";
24 | db.TimeSeriesAdd("my_ts", timestamp, 0.0);
25 | redis.Close();
26 | }
27 |
28 | ///
29 | /// Example for using TimeStamp as long value.
30 | /// The TimeSeriesAdd method gets a TimeStamp type parameter, which in this case the value 1
31 | /// is implicitly casted into a new TimeStamp object.
32 | ///
33 | public static void LongAdd()
34 | {
35 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
36 | IDatabase db = redis.GetDatabase();
37 | TimeStamp timestamp = 1;
38 | db.TimeSeriesAdd("my_ts", timestamp, 0.0);
39 | redis.Close();
40 | }
41 |
42 | ///
43 | /// Example for using TimeStamp as DateTime value.
44 | /// The TimeSeriesAdd method gets a TimeStamp type parameter, which in this case the value DateTime.UtcNow
45 | /// is implicitly casted into a new TimeStamp object.
46 | ///
47 | public static void DateTimeAdd()
48 | {
49 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
50 | IDatabase db = redis.GetDatabase();
51 | TimeStamp timestamp = DateTime.UtcNow;
52 | db.TimeSeriesAdd("my_ts", timestamp, 0.0);
53 | redis.Close();
54 | }
55 |
56 | ///
57 | /// Example for back-fill time-series sample.
58 | /// In order to avoid the BLOCK mode exeption must specify the duplicate policy.
59 | ///
60 | public static void DuplicatedAdd()
61 | {
62 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
63 | IDatabase db = redis.GetDatabase();
64 | TimeStamp timestamp = DateTime.UtcNow;
65 | db.TimeSeriesAdd("my_ts", timestamp, 1);
66 | db.TimeSeriesAdd("my_ts", timestamp, 0, duplicatePolicy: TsDuplicatePolicy.MIN);
67 | redis.Close();
68 | }
69 |
70 | ///
71 | /// Example for time-series creation parameters with ADD.
72 | /// Named arguments are used in the same manner of TimeSeriesCreate.
73 | ///
74 | public static void ParameterizedAdd()
75 | {
76 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
77 | IDatabase db = redis.GetDatabase();
78 | TimeStamp timestamp = "*";
79 | var label = new TimeSeriesLabel("key", "value");
80 | var labels = new List { label };
81 | db.TimeSeriesAdd("my_ts", timestamp, 0.0, retentionTime:5000, labels:labels, uncompressed:true);
82 | redis.Close();
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestIncrBy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestAPI
8 | {
9 | public class TestIncrBy : AbstractTimeSeriesTest, IDisposable
10 | {
11 | private readonly string key = "INCRBY_TESTS";
12 |
13 | public TestIncrBy(RedisFixture redisFixture) : base(redisFixture) { }
14 |
15 | public void Dispose()
16 | {
17 | redisFixture.Redis.GetDatabase().KeyDelete(key);
18 | }
19 |
20 | [Fact]
21 | public void TestDefaultIncrBy()
22 | {
23 | double value = 5.5;
24 | IDatabase db = redisFixture.Redis.GetDatabase();
25 | Assert.True(db.TimeSeriesIncrBy(key, value) > 0);
26 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
27 | }
28 |
29 | [Fact]
30 | public void TestStarIncrBy()
31 | {
32 | double value = 5.5;
33 | IDatabase db = redisFixture.Redis.GetDatabase();
34 | Assert.True(db.TimeSeriesIncrBy(key, value, timestamp: "*") > 0);
35 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
36 | }
37 |
38 | [Fact]
39 | public void TestIncrByTimeStamp()
40 | {
41 | double value = 5.5;
42 | IDatabase db = redisFixture.Redis.GetDatabase();
43 | TimeStamp timeStamp = DateTime.UtcNow;
44 | Assert.Equal(timeStamp, db.TimeSeriesIncrBy(key, value, timestamp: timeStamp));
45 | Assert.Equal(new TimeSeriesTuple(timeStamp, value), db.TimeSeriesGet(key));
46 | }
47 |
48 | [Fact]
49 | public void TestDefaultIncrByWithRetentionTime()
50 | {
51 | double value = 5.5;
52 | long retentionTime = 5000;
53 | IDatabase db = redisFixture.Redis.GetDatabase();
54 | Assert.True(db.TimeSeriesIncrBy(key, value, retentionTime: retentionTime) > 0);
55 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
56 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
57 | Assert.Equal(retentionTime, info.RetentionTime);
58 | }
59 |
60 | [Fact]
61 | public void TestDefaultIncrByWithLabels()
62 | {
63 | double value = 5.5;
64 | TimeSeriesLabel label = new TimeSeriesLabel("key", "value");
65 | IDatabase db = redisFixture.Redis.GetDatabase();
66 | var labels = new List { label };
67 | Assert.True(db.TimeSeriesIncrBy(key, value, labels: labels) > 0);
68 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
69 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
70 | Assert.Equal(labels, info.Labels);
71 | }
72 |
73 | [Fact]
74 | public void TestDefaultIncrByWithUncompressed()
75 | {
76 | double value = 5.5;
77 | IDatabase db = redisFixture.Redis.GetDatabase();
78 | Assert.True(db.TimeSeriesIncrBy(key, value, uncompressed:true) > 0);
79 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
80 | }
81 |
82 | [Fact]
83 | public void TestWrongParameters()
84 | {
85 | double value = 5.5;
86 | IDatabase db = redisFixture.Redis.GetDatabase();
87 | var ex = Assert.Throws(() => db.TimeSeriesIncrBy(key, value, timestamp: "+"));
88 | Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
89 | ex = Assert.Throws(() => db.TimeSeriesIncrBy(key, value, timestamp: "-"));
90 | Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestDecrBy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestAPI
8 | {
9 | public class TestDecrBy : AbstractTimeSeriesTest, IDisposable
10 | {
11 | private readonly string key = "DECRBY_TESTS";
12 |
13 | public TestDecrBy(RedisFixture redisFixture) : base(redisFixture) {}
14 |
15 | public void Dispose()
16 | {
17 | redisFixture.Redis.GetDatabase().KeyDelete(key);
18 | }
19 |
20 | [Fact]
21 | public void TestDefaultDecrBy()
22 | {
23 | double value = 5.5;
24 | IDatabase db = redisFixture.Redis.GetDatabase();
25 | Assert.True(db.TimeSeriesDecrBy(key, -value) > 0);
26 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
27 | }
28 |
29 | [Fact]
30 | public void TestStarDecrBy()
31 | {
32 | double value = 5.5;
33 | IDatabase db = redisFixture.Redis.GetDatabase();
34 | Assert.True(db.TimeSeriesDecrBy(key, -value, timestamp: "*") > 0);
35 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
36 | }
37 |
38 | [Fact]
39 | public void TestDecrByTimeStamp()
40 | {
41 | double value = 5.5;
42 | IDatabase db = redisFixture.Redis.GetDatabase();
43 | TimeStamp timeStamp = DateTime.UtcNow;
44 | Assert.Equal(timeStamp, db.TimeSeriesDecrBy(key, -value, timestamp: timeStamp));
45 | Assert.Equal(new TimeSeriesTuple(timeStamp, value), db.TimeSeriesGet(key));
46 | }
47 |
48 | [Fact]
49 | public void TestDefaultDecrByWithRetentionTime()
50 | {
51 | double value = 5.5;
52 | long retentionTime = 5000;
53 | IDatabase db = redisFixture.Redis.GetDatabase();
54 | Assert.True(db.TimeSeriesDecrBy(key, -value, retentionTime: retentionTime) > 0);
55 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
56 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
57 | Assert.Equal(retentionTime, info.RetentionTime);
58 | }
59 |
60 | [Fact]
61 | public void TestDefaultDecrByWithLabels()
62 | {
63 | double value = 5.5;
64 | TimeSeriesLabel label = new TimeSeriesLabel("key", "value");
65 | IDatabase db = redisFixture.Redis.GetDatabase();
66 | var labels = new List { label };
67 | Assert.True(db.TimeSeriesDecrBy(key, -value, labels: labels) > 0);
68 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
69 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
70 | Assert.Equal(labels, info.Labels);
71 | }
72 |
73 | [Fact]
74 | public void TestDefaultDecrByWithUncompressed()
75 | {
76 | double value = 5.5;
77 | IDatabase db = redisFixture.Redis.GetDatabase();
78 | Assert.True(db.TimeSeriesDecrBy(key, -value, uncompressed: true) > 0);
79 | Assert.Equal(value, db.TimeSeriesGet(key).Val);
80 | }
81 |
82 | [Fact]
83 | public void TestWrongParameters()
84 | {
85 | double value = 5.5;
86 | IDatabase db = redisFixture.Redis.GetDatabase();
87 | var ex = Assert.Throws(() => db.TimeSeriesDecrBy(key, value, timestamp: "+"));
88 | Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
89 | ex = Assert.Throws(() => db.TimeSeriesDecrBy(key, value, timestamp: "-"));
90 | Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestRulesAsync.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using StackExchange.Redis;
6 | using NRedisTimeSeries.Commands.Enums;
7 | using NRedisTimeSeries.DataTypes;
8 | using Xunit;
9 |
10 | namespace NRedisTimeSeries.Test.TestAPI
11 | {
12 | public class TestRulesAsync : AbstractTimeSeriesTest
13 | {
14 | public TestRulesAsync(RedisFixture redisFixture) : base(redisFixture) { }
15 |
16 | [Fact]
17 | public async Task TestRulesAdditionDeletion()
18 | {
19 | var key = CreateKeyName();
20 | var db = redisFixture.Redis.GetDatabase();
21 | await db.TimeSeriesCreateAsync(key);
22 | var aggregations = (TsAggregation[])Enum.GetValues(typeof(TsAggregation));
23 |
24 | foreach (var aggregation in aggregations)
25 | {
26 | await db.TimeSeriesCreateAsync($"{key}:{aggregation}");
27 | }
28 |
29 | var timeBucket = 50L;
30 | var rules = new List();
31 | var rulesMap = new Dictionary();
32 | foreach (var aggregation in aggregations)
33 | {
34 | var rule = new TimeSeriesRule($"{key}:{aggregation}", timeBucket, aggregation);
35 | rules.Add(rule);
36 | rulesMap[aggregation] = rule;
37 | Assert.True(await db.TimeSeriesCreateRuleAsync(key, rule));
38 |
39 | var info = await db.TimeSeriesInfoAsync(key);
40 | Assert.Equal(rules, info.Rules);
41 | }
42 |
43 | foreach (var aggregation in aggregations)
44 | {
45 | var rule = rulesMap[aggregation];
46 | rules.Remove(rule);
47 | Assert.True(await db.TimeSeriesDeleteRuleAsync(key, rule.DestKey));
48 |
49 | var info = await db.TimeSeriesInfoAsync(key);
50 | Assert.Equal(rules, info.Rules);
51 | }
52 |
53 | await db.KeyDeleteAsync(aggregations.Select(i => (RedisKey)$"{key}:{i}").ToArray());
54 | }
55 |
56 | [Fact]
57 | public async Task TestNonExistingSrc()
58 | {
59 | var key = CreateKeyName();
60 | var aggKey = $"{key}:{TsAggregation.Avg}";
61 | var db = redisFixture.Redis.GetDatabase();
62 | await db.TimeSeriesCreateAsync(aggKey);
63 | var rule = new TimeSeriesRule(aggKey, 50, TsAggregation.Avg);
64 | var ex = await Assert.ThrowsAsync(async () => await db.TimeSeriesCreateRuleAsync(key, rule));
65 | Assert.Equal("ERR TSDB: the key does not exist", ex.Message);
66 |
67 | ex = await Assert.ThrowsAsync(async () => await db.TimeSeriesDeleteRuleAsync(key, aggKey));
68 | Assert.Equal("ERR TSDB: the key does not exist", ex.Message);
69 |
70 | await db.KeyDeleteAsync(aggKey);
71 | }
72 |
73 | [Fact]
74 | public async Task TestNonExisitingDestinaion()
75 | {
76 | var key = CreateKeyName();
77 | var aggKey = $"{key}:{TsAggregation.Avg}";
78 | var db = redisFixture.Redis.GetDatabase();
79 | await db.TimeSeriesCreateAsync(key);
80 | var rule = new TimeSeriesRule(aggKey, 50, TsAggregation.Avg);
81 | var ex = await Assert.ThrowsAsync(async () => await db.TimeSeriesCreateRuleAsync(key, rule));
82 | Assert.Equal("ERR TSDB: the key does not exist", ex.Message);
83 |
84 | ex = await Assert.ThrowsAsync(async () => await db.TimeSeriesDeleteRuleAsync(key, aggKey));
85 | Assert.Equal("ERR TSDB: compaction rule does not exist", ex.Message);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Example/AddExampleAsync.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using StackExchange.Redis;
5 | using NRedisTimeSeries.Commands.Enums;
6 | using NRedisTimeSeries.DataTypes;
7 |
8 | namespace NRedisTimeSeries.Example
9 | {
10 | ///
11 | /// Examples for NRedisTimeSeries async API for adding new sample to time series.
12 | ///
13 | internal class AddAsyncExample
14 | {
15 | ///
16 | /// Example for using RedisTimeSeries default "*" charecter for system time.
17 | /// The TimeSeriesAdd method gets a TimeStamp type parameter, which in this case the string "*"
18 | /// is implicitly casted into a new TimeStamp object.
19 | ///
20 | public static async Task DefaultAddAsync()
21 | {
22 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
23 | IDatabase db = redis.GetDatabase();
24 | TimeStamp timestamp = "*";
25 | await db.TimeSeriesAddAsync("my_ts", timestamp, 0.0);
26 | redis.Close();
27 | }
28 |
29 | ///
30 | /// Example for using TimeStamp as long value.
31 | /// The TimeSeriesAdd method gets a TimeStamp type parameter, which in this case the value 1
32 | /// is implicitly casted into a new TimeStamp object.
33 | ///
34 | public static async Task LongAddAsync()
35 | {
36 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
37 | IDatabase db = redis.GetDatabase();
38 | TimeStamp timestamp = 1;
39 | await db.TimeSeriesAddAsync("my_ts", timestamp, 0.0);
40 | redis.Close();
41 | }
42 |
43 | ///
44 | /// Example for using TimeStamp as DateTime value.
45 | /// The TimeSeriesAdd method gets a TimeStamp type parameter, which in this case the value DateTime.UtcNow
46 | /// is implicitly casted into a new TimeStamp object.
47 | ///
48 | public static async Task DateTimeAddAsync()
49 | {
50 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
51 | IDatabase db = redis.GetDatabase();
52 | TimeStamp timestamp = DateTime.UtcNow;
53 | await db.TimeSeriesAddAsync("my_ts", timestamp, 0.0);
54 | redis.Close();
55 | }
56 |
57 | ///
58 | /// Example for back-fill time-series sample.
59 | /// In order to avoid the BLOCK mode exeption must specify the duplicate policy.
60 | ///
61 | public static async void DuplicatedAddAsync()
62 | {
63 |
64 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
65 | IDatabase db = redis.GetDatabase();
66 | TimeStamp timestamp = DateTime.UtcNow;
67 | await db.TimeSeriesAddAsync("my_ts", timestamp, 1);
68 | await db.TimeSeriesAddAsync("my_ts", timestamp, 0, duplicatePolicy: TsDuplicatePolicy.MIN);
69 | redis.Close();
70 | }
71 |
72 | ///
73 | /// Example for time-series creation parameters with ADD.
74 | /// Named arguments are used in the same manner of TimeSeriesCreate.
75 | ///
76 | public static async Task ParameterizedAddAsync()
77 | {
78 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
79 | IDatabase db = redis.GetDatabase();
80 | TimeStamp timestamp = "*";
81 | var label = new TimeSeriesLabel("key", "value");
82 | var labels = new List { label };
83 | await db.TimeSeriesAddAsync("my_ts", timestamp, 0.0, retentionTime:5000, labels:labels, uncompressed:true);
84 | redis.Close();
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/RedisTimeSeries/NRedisTimeSeries)
2 | [](https://circleci.com/gh/RedisTimeSeries/NRedisTimeSeries/tree/master)
3 | [](https://github.com/RedisTimeSeries/NRedisTimeSeries/releases/latest)
4 | [](https://codecov.io/gh/RedisTimeSeries/NRedisTimeSeries)
5 | [](https://snyk.io/test/github/RedisTimeSeries/NRedisTimeSeries?targetFile=NRedisTimeSeries/NRedisTimeSeries.csproj)
6 | [](https://www.nuget.org/packages/NRedisTimeSeries/)
7 |
8 | # NRedisTimeSeries
9 | [](https://forum.redislabs.com/c/modules/redistimeseries)
10 | [](https://discord.gg/KExRgMb)
11 |
12 | .Net Client for RedisTimeSeries
13 |
14 | ## Deprecation notice
15 |
16 | As of [nredisstack 0.4.1](https://github.com/redis/nredisstack) this library is deprecated. It's features have been merged into [nredisstack](https://github.com/redis/nredisstack. Please either install it [from nuget](https://www.nuget.org/packages/NRedisStack) or [the repo](https://github.com/redis/nredisstack).
17 |
18 |
19 | ## API
20 | The complete documentation of RedisTimeSeries's commands can be found at [RedisTimeSeries's website](http://redistimeseries.io/).
21 |
22 | ## Usage example
23 |
24 | ```C#
25 | ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
26 | IDatabase db = redis.GetDatabase();
27 |
28 | // Create
29 | var label = new TimeSeriesLabel("Time", "Series");
30 | db.TimeSeriesCreate("test", retentionTime: 5000, labels: new List { label }, duplicatePolicy: TsDuplicatePolicy.MAX);
31 |
32 | // Alter
33 | label = new TimeSeriesLabel("Alter", "label");
34 | db.TimeSeriesAlter("test", retentionTime: 0, labels: new List { label });
35 |
36 | // Add
37 | db.TimeSeriesAdd("test", 1, 1.12);
38 | db.TimeSeriesAdd("test", 1, 1.13, duplicatePolicy: TsDuplicatePolicy.LAST);
39 |
40 | // MAdd
41 | var sequence = new List<(string, TimeStamp, double)>(3);
42 | sequence.Add(("test", "*", 0.0));
43 | sequence.Add(("test", DateTime.UtcNow, 0.0));
44 | sequence.Add(("test", 1, 1.0));
45 | db.TimeSeriesMAdd(sequence);
46 |
47 | // Rule
48 | db.TimeSeriesCreate("sumRule");
49 | TimeSeriesRule rule = new TimeSeriesRule("sumRule", 20, TsAggregation.Sum);
50 | db.TimeSeriesCreateRule("test", rule);
51 | db.TimeSeriesAdd("test", "*", 1);
52 | db.TimeSeriesAdd("test", "*", 2);
53 | db.TimeSeriesDeleteRule("test", "sumRule");
54 | db.KeyDelete("sumRule");
55 |
56 | // Range
57 | db.TimeSeriesRange("test", "-", "+");
58 | db.TimeSeriesRange("test", "-", "+", aggregation: TsAggregation.Avg, timeBucket: 10);
59 |
60 | // Get
61 | db.TimeSeriesGet("test");
62 |
63 | // Info
64 | TimeSeriesInformation info = db.TimeSeriesInfo("test");
65 |
66 | // DEL
67 | db.KeyDelete("test");
68 | ```
69 |
70 | ## Further notes on back-filling time series
71 |
72 | Since [RedisTimeSeries 1.4](https://github.com/RedisTimeSeries/RedisTimeSeries/releases/tag/v1.4.5) we've added the ability to back-fill time series, with different duplicate policies.
73 |
74 | The default behavior is to block updates to the same timestamp, and you can control it via the `duplicatePolicy` argument. You can check in detail the [duplicate policy documentation](https://oss.redislabs.com/redistimeseries/configuration/#duplicate_policy).
75 |
76 |
77 | See the [Example project](NRedisTimeSeries.Example) for commands reference
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestCreate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using StackExchange.Redis;
4 | using NRedisTimeSeries;
5 | using NRedisTimeSeries.DataTypes;
6 | using NRedisTimeSeries.Commands;
7 | using NRedisTimeSeries.Commands.Enums;
8 | using Xunit;
9 |
10 | namespace NRedisTimeSeries.Test.TestAPI
11 | {
12 | public class TestCreate : AbstractTimeSeriesTest, IDisposable
13 | {
14 | private readonly string key = "CREATE_TESTS";
15 |
16 | public TestCreate(RedisFixture redisFixture) : base(redisFixture) { }
17 |
18 | public void Dispose()
19 | {
20 | redisFixture.Redis.GetDatabase().KeyDelete(key);
21 | }
22 |
23 | [Fact]
24 | public void TestCreateOK()
25 | {
26 | IDatabase db = redisFixture.Redis.GetDatabase();
27 | Assert.True(db.TimeSeriesCreate(key));
28 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
29 | }
30 |
31 | [Fact]
32 | public void TestCreateRetentionTime()
33 | {
34 | long retentionTime = 5000;
35 | IDatabase db = redisFixture.Redis.GetDatabase();
36 | Assert.True(db.TimeSeriesCreate(key, retentionTime: retentionTime));
37 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
38 | Assert.Equal(retentionTime, info.RetentionTime);
39 | }
40 |
41 | [Fact]
42 | public void TestCreateLabels()
43 | {
44 | TimeSeriesLabel label = new TimeSeriesLabel("key", "value");
45 | var labels = new List { label };
46 | IDatabase db = redisFixture.Redis.GetDatabase();
47 | Assert.True(db.TimeSeriesCreate(key, labels: labels));
48 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
49 | Assert.Equal(labels, info.Labels);
50 | }
51 |
52 | [Fact]
53 | public void TestCreateEmptyLabels()
54 | {
55 | var labels = new List();
56 | IDatabase db = redisFixture.Redis.GetDatabase();
57 | Assert.True(db.TimeSeriesCreate(key, labels: labels));
58 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
59 | Assert.Equal(labels, info.Labels);
60 | }
61 |
62 | [Fact]
63 | public void TestCreateUncompressed()
64 | {
65 | IDatabase db = redisFixture.Redis.GetDatabase();
66 | Assert.True(db.TimeSeriesCreate(key, uncompressed: true));
67 | }
68 |
69 | [Fact]
70 | public void TestCreatehDuplicatePolicyFirst()
71 | {
72 | IDatabase db = redisFixture.Redis.GetDatabase();
73 | Assert.True(db.TimeSeriesCreate(key, duplicatePolicy: TsDuplicatePolicy.FIRST));
74 | }
75 |
76 | [Fact]
77 | public void TestCreatehDuplicatePolicyLast()
78 | {
79 | IDatabase db = redisFixture.Redis.GetDatabase();
80 | Assert.True(db.TimeSeriesCreate(key, duplicatePolicy: TsDuplicatePolicy.LAST));
81 | }
82 |
83 | [Fact]
84 | public void TestCreatehDuplicatePolicyMin()
85 | {
86 | IDatabase db = redisFixture.Redis.GetDatabase();
87 | Assert.True(db.TimeSeriesCreate(key, duplicatePolicy: TsDuplicatePolicy.MIN));
88 | }
89 |
90 | [Fact]
91 | public void TestCreatehDuplicatePolicyMax()
92 | {
93 | IDatabase db = redisFixture.Redis.GetDatabase();
94 | Assert.True(db.TimeSeriesCreate(key, duplicatePolicy: TsDuplicatePolicy.MAX));
95 | }
96 |
97 | [Fact]
98 | public void TestCreatehDuplicatePolicySum()
99 | {
100 | IDatabase db = redisFixture.Redis.GetDatabase();
101 | Assert.True(db.TimeSeriesCreate(key, duplicatePolicy: TsDuplicatePolicy.SUM));
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestMAddAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using StackExchange.Redis;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 |
8 | namespace NRedisTimeSeries.Test.TestAPI
9 | {
10 | public class TestMAddAsync : AbstractTimeSeriesTest
11 | {
12 | public TestMAddAsync(RedisFixture redisFixture) : base(redisFixture) { }
13 |
14 |
15 | [Fact]
16 | public async Task TestStarMADD()
17 | {
18 | var keys = CreateKeyNames(2);
19 |
20 | IDatabase db = redisFixture.Redis.GetDatabase();
21 |
22 | foreach (string key in keys)
23 | {
24 | await db.TimeSeriesCreateAsync(key);
25 | }
26 |
27 | List<(string, TimeStamp, double)> sequence = new List<(string, TimeStamp, double)>(keys.Length);
28 | foreach (var keyname in keys)
29 | {
30 | sequence.Add((keyname, "*", 1.1));
31 | }
32 | var response = await db.TimeSeriesMAddAsync(sequence);
33 |
34 | Assert.Equal(keys.Length, response.Count);
35 |
36 | foreach (var key in keys)
37 | {
38 | TimeSeriesInformation info = await db.TimeSeriesInfoAsync(key);
39 | Assert.True(info.FirstTimeStamp > 0);
40 | Assert.Equal(info.FirstTimeStamp, info.LastTimeStamp);
41 | }
42 | }
43 |
44 |
45 | [Fact]
46 | public async Task TestSuccessfulMAdd()
47 | {
48 | var keys = CreateKeyNames(2);
49 | var db = redisFixture.Redis.GetDatabase();
50 |
51 | foreach (var key in keys)
52 | {
53 | await db.TimeSeriesCreateAsync(key);
54 | }
55 |
56 | var sequence = new List<(string, TimeStamp, double)>(keys.Length);
57 | var timestamps = new List(keys.Length);
58 | foreach (var keyname in keys)
59 | {
60 | var now = DateTime.UtcNow;
61 | timestamps.Add(now);
62 | sequence.Add((keyname, now, 1.1));
63 | }
64 |
65 | var response = await db.TimeSeriesMAddAsync(sequence);
66 | Assert.Equal(timestamps.Count, response.Count);
67 | for (var i = 0; i < response.Count; i++)
68 | {
69 | Assert.Equal(timestamps[i], response[i]);
70 | }
71 | }
72 |
73 | [Fact]
74 | public async Task TestOverrideMAdd()
75 | {
76 | var keys = CreateKeyNames(2);
77 | var db = redisFixture.Redis.GetDatabase();
78 |
79 | foreach (var key in keys)
80 | {
81 | await db.TimeSeriesCreateAsync(key);
82 | }
83 |
84 | var oldTimeStamps = new List();
85 | foreach (var keyname in keys)
86 | {
87 | oldTimeStamps.Add(DateTime.UtcNow);
88 | }
89 |
90 | var sequence = new List<(string, TimeStamp, double)>(keys.Length);
91 | foreach (var keyname in keys)
92 | {
93 | sequence.Add((keyname, DateTime.UtcNow, 1.1));
94 | }
95 |
96 | await db.TimeSeriesMAddAsync(sequence);
97 | sequence.Clear();
98 |
99 | // Override the same events should not throw an error
100 | for (var i = 0; i < keys.Length; i++)
101 | {
102 | sequence.Add((keys[i], oldTimeStamps[i], 1.1));
103 | }
104 |
105 | var response = await db.TimeSeriesMAddAsync(sequence);
106 |
107 | Assert.Equal(oldTimeStamps.Count, response.Count);
108 | for(int i = 0; i < response.Count; i++)
109 | {
110 | Assert.Equal(oldTimeStamps[i], response[i]);
111 | }
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestMADD.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NRedisTimeSeries.DataTypes;
4 | using StackExchange.Redis;
5 | using Xunit;
6 |
7 | namespace NRedisTimeSeries.Test.TestAPI
8 | {
9 | public class TestMADD : AbstractTimeSeriesTest, IDisposable
10 | {
11 |
12 | private readonly string[] keys = { "MADD_TESTS_1", "MADD_TESTS_2" };
13 |
14 | public TestMADD(RedisFixture redisFixture) : base(redisFixture) { }
15 |
16 | public void Dispose()
17 | {
18 | foreach(string key in keys)
19 | {
20 | redisFixture.Redis.GetDatabase().KeyDelete(key);
21 | }
22 | }
23 |
24 | [Fact]
25 | public void TestStarMADD()
26 | {
27 |
28 | IDatabase db = redisFixture.Redis.GetDatabase();
29 |
30 | foreach (string key in keys)
31 | {
32 | db.TimeSeriesCreate(key);
33 | }
34 | List<(string, TimeStamp, double)> sequence = new List<(string, TimeStamp, double)>(keys.Length);
35 | foreach (var keyname in keys)
36 | {
37 | sequence.Add((keyname, "*", 1.1));
38 | }
39 | var response = db.TimeSeriesMAdd(sequence);
40 |
41 | Assert.Equal(keys.Length, response.Count);
42 |
43 | foreach (var key in keys)
44 | {
45 | TimeSeriesInformation info = db.TimeSeriesInfo(key);
46 | Assert.True(info.FirstTimeStamp > 0);
47 | Assert.Equal(info.FirstTimeStamp, info.LastTimeStamp);
48 | }
49 | }
50 |
51 | [Fact]
52 | public void TestSuccessfulMADD()
53 | {
54 |
55 | IDatabase db = redisFixture.Redis.GetDatabase();
56 |
57 | foreach (string key in keys)
58 | {
59 | db.TimeSeriesCreate(key);
60 | }
61 |
62 | List<(string, TimeStamp, double)> sequence = new List<(string, TimeStamp, double)>(keys.Length);
63 | List timestamps = new List(keys.Length);
64 | foreach (var keyname in keys)
65 | {
66 | DateTime now = DateTime.UtcNow;
67 | timestamps.Add(now);
68 | sequence.Add((keyname, now, 1.1));
69 | }
70 | var response = db.TimeSeriesMAdd(sequence);
71 |
72 | Assert.Equal(timestamps.Count, response.Count);
73 | for(int i = 0; i < response.Count; i++)
74 | {
75 | Assert.Equal(timestamps[i], response[i]);
76 | }
77 | }
78 |
79 | [Fact]
80 | public void TestOverrideMADD()
81 | {
82 | IDatabase db = redisFixture.Redis.GetDatabase();
83 |
84 | foreach (string key in keys)
85 | {
86 | db.TimeSeriesCreate(key);
87 | }
88 |
89 | List oldTimeStamps = new List();
90 | foreach (var keyname in keys)
91 | {
92 | oldTimeStamps.Add(DateTime.UtcNow);
93 | }
94 |
95 | List<(string, TimeStamp, double)> sequence = new List<(string, TimeStamp, double)>(keys.Length);
96 | foreach (var keyname in keys)
97 | {
98 | sequence.Add((keyname, DateTime.UtcNow, 1.1));
99 | }
100 | db.TimeSeriesMAdd(sequence);
101 |
102 | sequence.Clear();
103 |
104 | // Override the same events should not throw an error
105 | for (int i =0; i < keys.Length; i++)
106 | {
107 | sequence.Add((keys[i], oldTimeStamps[i], 1.1));
108 | }
109 | var response = db.TimeSeriesMAdd(sequence);
110 |
111 | Assert.Equal(oldTimeStamps.Count, response.Count);
112 | for(int i = 0; i < response.Count; i++)
113 | {
114 | Assert.Equal(oldTimeStamps[i], response[i]);
115 | }
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/NRedisTimeSeries.Test/TestAPI/TestCreateAsync.cs:
--------------------------------------------------------------------------------
1 | using NRedisTimeSeries.DataTypes;
2 | using NRedisTimeSeries.Commands.Enums;
3 | using NRedisTimeSeries.Commands;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 |
8 | namespace NRedisTimeSeries.Test.TestAPI
9 | {
10 | public class TestCreateAsync : AbstractTimeSeriesTest
11 | {
12 | public TestCreateAsync(RedisFixture redisFixture) : base(redisFixture) { }
13 |
14 | [Fact]
15 | public async Task TestCreateOK()
16 | {
17 | var key = CreateKeyName();
18 | var db = redisFixture.Redis.GetDatabase();
19 | Assert.True(await db.TimeSeriesCreateAsync(key));
20 | }
21 |
22 | [Fact]
23 | public async Task TestCreateRetentionTime()
24 | {
25 | var key = CreateKeyName();
26 | long retentionTime = 5000;
27 | var db = redisFixture.Redis.GetDatabase();
28 | Assert.True(await db.TimeSeriesCreateAsync(key, retentionTime: retentionTime));
29 |
30 | var info = await db.TimeSeriesInfoAsync(key);
31 | Assert.Equal(retentionTime, info.RetentionTime);
32 | }
33 |
34 | [Fact]
35 | public async Task TestCreateLabels()
36 | {
37 | var key = CreateKeyName();
38 | var label = new TimeSeriesLabel("key", "value");
39 | var labels = new List { label };
40 | var db = redisFixture.Redis.GetDatabase();
41 | Assert.True(await db.TimeSeriesCreateAsync(key, labels: labels));
42 |
43 | var info = await db.TimeSeriesInfoAsync(key);
44 | Assert.Equal(labels, info.Labels);
45 | }
46 |
47 | [Fact]
48 | public async Task TestCreateEmptyLabels()
49 | {
50 | var key = CreateKeyName();
51 | var labels = new List();
52 | var db = redisFixture.Redis.GetDatabase();
53 | Assert.True(await db.TimeSeriesCreateAsync(key, labels: labels));
54 |
55 | var info = await db.TimeSeriesInfoAsync(key);
56 | Assert.Equal(labels, info.Labels);
57 | }
58 |
59 | [Fact]
60 | public async Task TestCreateUncompressed()
61 | {
62 | var key = CreateKeyName();
63 | var db = redisFixture.Redis.GetDatabase();
64 | Assert.True(await db.TimeSeriesCreateAsync(key, uncompressed: true));
65 | }
66 |
67 | [Fact]
68 | public async void TestCreatehDuplicatePolicyFirst()
69 | {
70 | var key = CreateKeyName();
71 | var db = redisFixture.Redis.GetDatabase();
72 | Assert.True(await db.TimeSeriesCreateAsync(key, duplicatePolicy: TsDuplicatePolicy.FIRST));
73 | }
74 |
75 | [Fact]
76 | public async void TestCreatehDuplicatePolicyLast()
77 | {
78 | var key = CreateKeyName();
79 | var db = redisFixture.Redis.GetDatabase();
80 | Assert.True(await db.TimeSeriesCreateAsync(key, duplicatePolicy: TsDuplicatePolicy.LAST));
81 | }
82 |
83 | [Fact]
84 | public async void TestCreatehDuplicatePolicyMin()
85 | {
86 | var key = CreateKeyName();
87 | var db = redisFixture.Redis.GetDatabase();
88 | Assert.True(await db.TimeSeriesCreateAsync(key, duplicatePolicy: TsDuplicatePolicy.MIN));
89 | }
90 |
91 | [Fact]
92 | public async void TestCreatehDuplicatePolicyMax()
93 | {
94 | var key = CreateKeyName();
95 | var db = redisFixture.Redis.GetDatabase();
96 | Assert.True(await db.TimeSeriesCreateAsync(key, duplicatePolicy: TsDuplicatePolicy.MAX));
97 | }
98 |
99 | [Fact]
100 | public async void TestCreatehDuplicatePolicySum()
101 | {
102 | var key = CreateKeyName();
103 | var db = redisFixture.Redis.GetDatabase();
104 | Assert.True(await db.TimeSeriesCreateAsync(key, duplicatePolicy: TsDuplicatePolicy.SUM));
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/DataTypes/TimeSeriesInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.Json;
3 | using System.Collections.Generic;
4 | using NRedisTimeSeries.Commands.Enums;
5 |
6 | namespace NRedisTimeSeries.DataTypes
7 | {
8 | ///
9 | /// This class represents the response for TS.INFO command.
10 | /// This object has Read-only properties and cannot be generated outside a TS.INFO response.
11 | ///
12 | public class TimeSeriesInformation
13 | {
14 | ///
15 | /// Total samples in the time-series.
16 | ///
17 | public long TotalSamples { get; private set; }
18 |
19 | ///
20 | /// Total number of bytes allocated for the time-series.
21 | ///
22 | public long MemoryUsage { get; private set; }
23 |
24 | ///
25 | /// First timestamp present in the time-series.
26 | ///
27 | public TimeStamp FirstTimeStamp { get; private set; }
28 |
29 | ///
30 | /// Last timestamp present in the time-series.
31 | ///
32 | public TimeStamp LastTimeStamp { get; private set; }
33 |
34 | ///
35 | /// Retention time, in milliseconds, for the time-series.
36 | ///
37 | public long RetentionTime { get; private set; }
38 |
39 | ///
40 | /// Number of Memory Chunks used for the time-series.
41 | ///
42 | public long ChunkCount { get; private set; }
43 |
44 | ///
45 | /// Maximum Number of samples per Memory Chunk.
46 | ///
47 | [ObsoleteAttribute("This method has been deprecated. Use ChunkSize instead.")]
48 | public long MaxSamplesPerChunk { get; private set; }
49 |
50 | ///
51 | /// Memory Chunk size in Bytes.
52 | ///
53 | public long ChunkSize { get; private set; }
54 |
55 | ///
56 | /// A readonly list of TimeSeriesLabel that represent metadata labels of the time-series.
57 | ///
58 | public IReadOnlyList Labels { get; private set; }
59 |
60 | ///
61 | /// Source key for the queries time series key.
62 | ///
63 | public string SourceKey { get; private set; }
64 |
65 | ///
66 | /// A readonly list of TimeSeriesRules that represent compaction Rules of the time-series.
67 | ///
68 | public IReadOnlyList Rules { get; private set; }
69 |
70 | ///
71 | /// The policy will define handling of duplicate samples.
72 | ///
73 | public TsDuplicatePolicy? DuplicatePolicy { get; private set; }
74 |
75 | internal TimeSeriesInformation(long totalSamples, long memoryUsage, TimeStamp firstTimeStamp, TimeStamp lastTimeStamp, long retentionTime, long chunkCount, long chunkSize, IReadOnlyList labels, string sourceKey, IReadOnlyList rules, TsDuplicatePolicy? policy)
76 | {
77 | TotalSamples = totalSamples;
78 | MemoryUsage = memoryUsage;
79 | FirstTimeStamp = firstTimeStamp;
80 | LastTimeStamp = lastTimeStamp;
81 | RetentionTime = retentionTime;
82 | ChunkCount = chunkCount;
83 | Labels = labels;
84 | SourceKey = sourceKey;
85 | Rules = rules;
86 | // backwards compatible with RedisTimeSeries < v1.4
87 | MaxSamplesPerChunk = chunkSize/16;
88 | ChunkSize = chunkSize;
89 | // configure what to do on duplicate sample > v1.4
90 | DuplicatePolicy = policy;
91 | }
92 |
93 | ///
94 | /// Implicit cast from TimeSeriesInformation to string.
95 | ///
96 | /// TimeSeriesInformation
97 | public static implicit operator string(TimeSeriesInformation info) => JsonSerializer.Serialize(info);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/NRedisTimeSeries/DataTypes/TimeStamp.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace NRedisTimeSeries.DataTypes
5 | {
6 | ///
7 | /// A class represents timestamp.
8 | /// Value can be either primitive long, DateTime or one of the strings "-", "+", "*".
9 | ///
10 | public class TimeStamp
11 | {
12 | private static readonly string[] constants = { "-", "+", "*" };
13 |
14 | ///
15 | /// TimeStamp value.
16 | ///
17 | public object Value { get; private set; }
18 |
19 | ///
20 | /// Build a TimeStamp from primitive long.
21 | ///
22 | /// long value
23 | public TimeStamp(long timestamp) => Value = timestamp;
24 |
25 | ///
26 | /// Build a TimeStamp from DateTime.
27 | ///
28 | /// DateTime value
29 | public TimeStamp(DateTime dateTime) => Value = dateTime.Ticks;
30 |
31 | ///
32 | /// Build a TimeStamp from one of the strings "-", "+", "*".
33 | /// If the string is none of the above a NotSupportedException is thrown.
34 | ///
35 | /// String value
36 | public TimeStamp(string timestamp)
37 | {
38 | if (Array.IndexOf(constants, timestamp) == -1)
39 | {
40 | throw new NotSupportedException(string.Format("The string {0} cannot be used", timestamp));
41 | }
42 | Value = timestamp;
43 | }
44 |
45 | ///
46 | /// Implicit cast from long to TimeStamp.
47 | ///
48 | /// long value.
49 | public static implicit operator TimeStamp(long l) => new TimeStamp(l);
50 |
51 | ///
52 | /// Implicit cast from TimeStamp to long.
53 | /// If the underlying timestamp value is not long or DateTime, an InvalidCastException is thrown.
54 | ///
55 | /// TimeStamp
56 | public static implicit operator long(TimeStamp ts) =>
57 | ts.Value is long value ? value : throw new InvalidCastException("Cannot convert string timestamp to long");
58 |
59 | ///
60 | /// Implicit cast from string to TimeStamp.
61 | /// Calls the string C'tor.
62 | ///
63 | /// String value
64 | public static implicit operator TimeStamp(string s) => new TimeStamp(s);
65 |
66 | ///
67 | /// Implicit cast from TimeStamp to string.
68 | ///
69 | /// TimeStamp
70 | public static implicit operator string(TimeStamp ts) => ts.Value.ToString();
71 |
72 | ///
73 | /// Implicit cast from DateTime to TimeStamp.
74 | ///
75 | /// DateTime value
76 | public static implicit operator TimeStamp(DateTime dateTime) => new TimeStamp(dateTime);
77 |
78 | ///
79 | /// Implicit cast from TimeStamp to DateTime.
80 | ///
81 | /// TimeStamp
82 | public static implicit operator DateTime(TimeStamp timeStamp) => new DateTime(timeStamp);
83 |
84 | ///
85 | /// Equality of TimeSeriesTuple objects
86 | ///
87 | /// Object to compare
88 | /// If two TimeStamp objects are equal
89 | public override bool Equals(object obj) =>
90 | obj is TimeStamp stamp && EqualityComparer