From 05cbaf7a5516f3ece25013c7a56b912e51e2b155 Mon Sep 17 00:00:00 2001
From: atakavci <58048133+atakavci@users.noreply.github.com>
Date: Mon, 22 Apr 2024 16:01:37 +0300
Subject: [PATCH 01/13] Update integration.yml

---
 .github/workflows/integration.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index de05bcc0..177755d9 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -148,6 +148,7 @@ jobs:
       USER_NAME: ${{ secrets.USER_NAME }}
       PASSWORD: ${{ secrets.PASSWORD }}
       ENDPOINT: ${{ secrets.ENDPOINT }}
+      
     steps:
       - uses: actions/checkout@v3
       - uses: Vampire/setup-wsl@v2
@@ -175,4 +176,4 @@ jobs:
         shell: cmd
         run: |
           START wsl ./redis-stack-server-${{env.redis_stack_version}}/bin/redis-stack-server &
-          dotnet test -f net481 --no-build --verbosity detailed
\ No newline at end of file
+          dotnet test -f net481 --no-build --verbosity detailed

From 072233d97bff5cffb139177a17221ee9f0251272 Mon Sep 17 00:00:00 2001
From: atakavci <58048133+atakavci@users.noreply.github.com>
Date: Mon, 22 Apr 2024 23:42:32 +0300
Subject: [PATCH 02/13] Update integration.yml

---
 .github/workflows/integration.yml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 177755d9..cd6de392 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -7,6 +7,11 @@ on:
       - '**/*.md'
     branches:
       - master
+      - ali/ClusterSupport2-p1
+      - ali/ClusterSupport2-p2
+      - ali/ClusterSupport2-p3
+      - ali/ClusterSupport2-p4
+      - ali/ClusterSupport2-p5
   pull_request:
   schedule:
     - cron: "0 1 * * *"

From a091a5de0147e1773cac053dba9ef8922526e029 Mon Sep 17 00:00:00 2001
From: atakavci <58048133+atakavci@users.noreply.github.com>
Date: Tue, 23 Apr 2024 00:27:40 +0300
Subject: [PATCH 03/13] Update integration.yml

---
 .github/workflows/integration.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index cd6de392..79e52a7f 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -15,6 +15,7 @@ on:
   pull_request:
   schedule:
     - cron: "0 1 * * *"
+  workflow_dispatch:
 
 concurrency:
   group: ${{ github.event.pull_request.number || github.ref }}-integration

From d750aabc46901a63c9ea910a7697594eb161842d Mon Sep 17 00:00:00 2001
From: atakavci <58048133+atakavci@users.noreply.github.com>
Date: Wed, 24 Apr 2024 11:30:17 +0300
Subject: [PATCH 04/13] Update integration.yml

---
 .github/workflows/integration.yml | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 79e52a7f..73eeed82 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -6,12 +6,7 @@ on:
       - 'docs/**'
       - '**/*.md'
     branches:
-      - master
       - ali/ClusterSupport2-p1
-      - ali/ClusterSupport2-p2
-      - ali/ClusterSupport2-p3
-      - ali/ClusterSupport2-p4
-      - ali/ClusterSupport2-p5
   pull_request:
   schedule:
     - cron: "0 1 * * *"

From 385e5e2052f34180d0a20c24662ec1e19e2a4237 Mon Sep 17 00:00:00 2001
From: atakavci <58048133+atakavci@users.noreply.github.com>
Date: Tue, 14 May 2024 13:13:06 +0300
Subject: [PATCH 05/13] Update .env.enterprise_oss_cluster

---
 .github/workflows/modes/.env.enterprise_oss_cluster | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/modes/.env.enterprise_oss_cluster b/.github/workflows/modes/.env.enterprise_oss_cluster
index 1b81f571..d8bb8ddd 100644
--- a/.github/workflows/modes/.env.enterprise_oss_cluster
+++ b/.github/workflows/modes/.env.enterprise_oss_cluster
@@ -5,4 +5,7 @@ RE_USERNAME=test@test.com
 RE_PASS=12345
 RE_CLUSTER_NAME=test
 RE_USE_OSS_CLUSTER=true
-RE_DB_PORT=6378
\ No newline at end of file
+RE_DB_PORT=6378
+oss_cluster=true
+oss_cluster_api_preferred_ip_type=external
+oss_cluster_api_preferred_endpoint_type=hostname

From b47c77fba6efb7d231cafba91a8b21d419d3a3cd Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Fri, 24 May 2024 18:00:21 +0300
Subject: [PATCH 06/13] timeseries ignore parameters with builder

---
 .../TimeSeries/DataTypes/TSParameters.cs      |  41 +++++
 .../TimeSeries/Literals/CommandArgs.cs        |   1 +
 src/NRedisStack/TimeSeries/TimeSeriesAux.cs   |   9 ++
 .../TimeSeries/TimeSeriesCommandsBuilder.cs   |  27 +++-
 .../TimeSeries/TimeSeriesParamsBuilder.cs     | 152 ++++++++++++++++++
 5 files changed, 229 insertions(+), 1 deletion(-)
 create mode 100644 src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs
 create mode 100644 src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs

diff --git a/src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs b/src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs
new file mode 100644
index 00000000..2046d5de
--- /dev/null
+++ b/src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs
@@ -0,0 +1,41 @@
+namespace NRedisStack
+{
+    public class TsBaseParams
+    {
+        protected object[] parameters;
+
+        internal TsBaseParams(object[] parameters)
+        {
+            this.parameters = parameters;
+        }
+
+        internal object[] GetAsArray()
+        {
+            return parameters.ToArray();
+        }
+    }
+
+    public class TsCreateParams : TsBaseParams
+    {
+        internal TsCreateParams(object[] parameters) : base(parameters) { }
+    }
+    public class TsAlterParams : TsBaseParams
+    {
+        internal TsAlterParams(object[] parameters) : base(parameters) { }
+    }
+
+    public class TsAddParams : TsBaseParams
+    {
+        internal TsAddParams(object[] parameters) : base(parameters) { }
+    }
+
+    public class TsIncrByParams : TsBaseParams
+    {
+        internal TsIncrByParams(object[] parameters) : base(parameters) { }
+    }
+
+    public class TsDecrByParams : TsBaseParams
+    {
+        internal TsDecrByParams(object[] parameters) : base(parameters) { }
+    }
+}
diff --git a/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs b/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs
index 7b17ed4a..3f484120 100644
--- a/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs
+++ b/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs
@@ -23,5 +23,6 @@ internal class TimeSeriesArgs
         public const string DEBUG = "DEBUG";
         public const string BUCKETTIMESTAMP = "BUCKETTIMESTAMP";
         public const string EMPTY = "EMPTY";
+        public const String VALUES = "VALUES";
     }
 }
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesAux.cs b/src/NRedisStack/TimeSeries/TimeSeriesAux.cs
index 54c20f65..033d9baa 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesAux.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesAux.cs
@@ -50,6 +50,15 @@ public static void AddUncompressed(this IList<object> args, bool? uncompressed)
                 args.Add(TimeSeriesArgs.UNCOMPRESSED);
             }
         }
+        public static void AddIgnoreValues(this IList<object> args, long? ignoreMaxTimeDiff, long? ignoreMaxValDiff)
+        {
+            if (ignoreMaxTimeDiff != null || ignoreMaxValDiff != null)
+            {
+                args.Add(TimeSeriesArgs.VALUES);
+                args.Add(ignoreMaxTimeDiff ?? 0);
+                args.Add(ignoreMaxValDiff ?? 0);
+            }
+        }
 
         public static void AddCount(this IList<object> args, long? count)
         {
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
index a9ae45a9..4edc8ed3 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
@@ -15,6 +15,11 @@ public static SerializedCommand Create(string key, long? retentionTime = null, I
             return new SerializedCommand(TS.CREATE, args);
         }
 
+        public static SerializedCommand Create(TsCreateParams parameters)
+        {
+            return new SerializedCommand(TS.CREATE, parameters.GetAsArray());
+        }
+
         #endregion
 
         #region Update
@@ -25,6 +30,11 @@ public static SerializedCommand Alter(string key, long? retentionTime = null, lo
             return new SerializedCommand(TS.ALTER, args);
         }
 
+        public static SerializedCommand Alter(TsAlterParams parameters)
+        {
+            return new SerializedCommand(TS.ALTER, parameters.GetAsArray());
+        }
+
         public static SerializedCommand Add(string key, TimeStamp timestamp, double value, long? retentionTime = null,
         IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null,
         long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
@@ -33,6 +43,11 @@ public static SerializedCommand Add(string key, TimeStamp timestamp, double valu
             return new SerializedCommand(TS.ADD, args);
         }
 
+        public static SerializedCommand Add(TsAddParams parameters)
+        {
+            return new SerializedCommand(TS.ADD, parameters.GetAsArray());
+        }
+
         public static SerializedCommand MAdd(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence)
         {
             var args = TimeSeriesAux.BuildTsMaddArgs(sequence);
@@ -45,10 +60,20 @@ public static SerializedCommand IncrBy(string key, double value, TimeStamp? time
             return new SerializedCommand(TS.INCRBY, args);
         }
 
+        public static SerializedCommand IncrBy(TsIncrByParams parameters)
+        {
+            return new SerializedCommand(TS.INCRBY, parameters.GetAsArray());
+        }
+
         public static SerializedCommand DecrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
             var args = TimeSeriesAux.BuildTsIncrDecrByArgs(key, value, timestamp, retentionTime, labels, uncompressed, chunkSizeBytes);
-            return (new SerializedCommand(TS.DECRBY, args));
+            return new SerializedCommand(TS.DECRBY, args);
+        }
+
+        public static SerializedCommand DecrBy(TsDecrByParams parameters)
+        {
+            return new SerializedCommand(TS.DECRBY, parameters.GetAsArray());
         }
 
         public static SerializedCommand Del(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp)
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs b/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
new file mode 100644
index 00000000..8ee97003
--- /dev/null
+++ b/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
@@ -0,0 +1,152 @@
+using NRedisStack.Literals;
+using NRedisStack.Literals.Enums;
+using NRedisStack.DataTypes;
+using NRedisStack.RedisStackCommands;
+using System.Collections.ObjectModel;
+
+namespace NRedisStack
+{
+
+    public abstract class TsBaseParamsBuilder<T> where T : TsBaseParamsBuilder<T>
+    {
+        internal string key;
+        internal long? retentionTime;
+        internal IReadOnlyCollection<TimeSeriesLabel>? labels;
+        internal long? chunkSizeBytes;
+        internal long? ignoreMaxTimeDiff;
+        internal long? ignoreMaxValDiff;
+        internal TsBaseParamsBuilder() { }
+
+        public T addKey(string key)
+        {
+            this.key = key;
+            return (T)this;
+        }
+        public T addRetentionTime(long? retentionTime)
+        {
+            this.retentionTime = retentionTime;
+            return (T)this;
+        }
+        public T addLabels(ReadOnlyCollection<TimeSeriesLabel>? labels)
+        {
+            this.labels = labels;
+            return (T)this;
+        }
+        public T addChunkSizeBytes(long? chunkSizeBytes)
+        {
+            this.chunkSizeBytes = chunkSizeBytes;
+            return (T)this;
+        }
+
+        public T addIgnoreMaxTimeDiff(long? ignoreMaxTimeDiff)
+        {
+            this.ignoreMaxTimeDiff = ignoreMaxTimeDiff;
+            return (T)this;
+        }
+        public T addIgnoreMaxValDiff(long? ignoreMaxValDiff)
+        {
+            this.ignoreMaxValDiff = ignoreMaxValDiff;
+            return (T)this;
+        }
+    }
+
+    public class TsCreateParamsBuilder : TsBaseParamsBuilder<TsCreateParamsBuilder>
+    {
+        private bool? uncompressed;
+        private TsDuplicatePolicy? duplicatePolicy;
+        public TsCreateParams build()
+        {
+            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+
+            var args = new List<object> { key };
+            args.AddRetentionTime(retentionTime);
+            args.AddChunkSize(chunkSizeBytes);
+            args.AddLabels(labels);
+            args.AddUncompressed(uncompressed);
+            args.AddDuplicatePolicy(duplicatePolicy);
+            args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
+            return new TsCreateParams(args.ToArray());
+        }
+    }
+
+    public class TsAlterParamsBuilder : TsBaseParamsBuilder<TsAlterParamsBuilder>
+    {
+        private TsDuplicatePolicy? duplicatePolicy;
+        public TsAlterParams build()
+        {
+            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+
+            var args = new List<object> { key };
+            args.AddRetentionTime(retentionTime);
+            args.AddChunkSize(chunkSizeBytes);
+            args.AddDuplicatePolicy(duplicatePolicy);
+            args.AddLabels(labels);
+            args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
+            return new TsAlterParams(args.ToArray());
+        }
+    }
+
+    public class TsAddParamsBuilder : TsBaseParamsBuilder<TsAddParamsBuilder>
+    {
+        private double value;
+        private TimeStamp timestamp;
+        private bool? uncompressed;
+        private TsDuplicatePolicy? duplicatePolicy;
+        public TsAddParams build()
+        {
+            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+
+            var args = new List<object> { key, timestamp.Value, value };
+            args.AddRetentionTime(retentionTime);
+            args.AddChunkSize(chunkSizeBytes);
+            args.AddLabels(labels);
+            args.AddUncompressed(uncompressed);
+            args.AddOnDuplicate(duplicatePolicy);
+            args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
+            return new TsAddParams(args.ToArray());
+        }
+    }
+
+    public class TsIncrByParamsBuilder : TsBaseParamsBuilder<TsIncrByParamsBuilder>
+    {
+        private double value;
+        private TimeStamp? timestamp;
+        private bool? uncompressed;
+        private TsDuplicatePolicy? duplicatePolicy;
+
+        public TsIncrByParams build()
+        {
+            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+
+            var args = new List<object> { key, value };
+            if (timestamp != null) args.AddTimeStamp(timestamp.Value);
+            args.AddRetentionTime(retentionTime);
+            args.AddChunkSize(chunkSizeBytes);
+            if (labels != null) args.AddLabels(labels);
+            args.AddUncompressed(uncompressed);
+            args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
+            return new TsIncrByParams(args.ToArray());
+        }
+    }
+
+    public class TsDecrByParamsBuilder : TsBaseParamsBuilder<TsDecrByParamsBuilder>
+    {
+        private double value;
+        private TimeStamp? timestamp;
+        private bool? uncompressed;
+        public TsDecrByParams build()
+        {
+            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+
+            var args = new List<object> { key, value };
+            if (timestamp != null) args.AddTimeStamp(timestamp.Value);
+            args.AddRetentionTime(retentionTime);
+            args.AddChunkSize(chunkSizeBytes);
+            if (labels != null) args.AddLabels(labels);
+            args.AddUncompressed(uncompressed);
+            args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
+            return new TsDecrByParams(args.ToArray());
+        }
+    }
+
+}
\ No newline at end of file

From 42363efaa3d5c87ecbb21072f2271e44f85fdb86 Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Tue, 28 May 2024 10:35:33 +0300
Subject: [PATCH 07/13] adding remaining builder methods and unit tests  #302

---
 .../TimeSeries/DataTypes/TSParameters.cs      |  75 ++++++-
 .../TimeSeries/Literals/CommandArgs.cs        |   2 +-
 src/NRedisStack/TimeSeries/TimeSeriesAux.cs   | 114 ----------
 .../TimeSeries/TimeSeriesCommands.cs          |  19 ++
 .../TimeSeries/TimeSeriesCommandsAsync.cs     |  17 ++
 .../TimeSeries/TimeSeriesCommandsBuilder.cs   |  49 +++--
 .../TimeSeries/TimeSeriesParamsBuilder.cs     | 197 +++++++++++++-----
 .../TimeSeries/TestAPI/TestAdd.cs             |  19 ++
 .../TimeSeries/TestAPI/TestAlter.cs           |  20 ++
 .../TimeSeries/TestAPI/TestCreate.cs          |  19 ++
 .../TimeSeries/TestAPI/TestDecrBy.cs          |  19 ++
 .../TimeSeries/TestAPI/TestIncrBy.cs          |  19 ++
 .../TimeSeries/TestAPI/TimeSeriesHelper.cs    |  25 +++
 13 files changed, 396 insertions(+), 198 deletions(-)
 create mode 100644 tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs

diff --git a/src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs b/src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs
index 2046d5de..f70e9629 100644
--- a/src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs
+++ b/src/NRedisStack/TimeSeries/DataTypes/TSParameters.cs
@@ -1,41 +1,96 @@
-namespace NRedisStack
+using NRedisStack.DataTypes;
+using NRedisStack.Literals.Enums;
+
+namespace NRedisStack
 {
     public class TsBaseParams
     {
-        protected object[] parameters;
+        protected IList<object> parameters;
 
-        internal TsBaseParams(object[] parameters)
+        internal TsBaseParams()
+        {
+            this.parameters = new List<object>();
+        }
+
+        internal TsBaseParams(IList<object> parameters)
         {
             this.parameters = parameters;
         }
 
-        internal object[] GetAsArray()
+        internal object[] ToArray(string key)
         {
+            parameters.Insert(0, key);
             return parameters.ToArray();
         }
     }
 
     public class TsCreateParams : TsBaseParams
     {
-        internal TsCreateParams(object[] parameters) : base(parameters) { }
+        internal TsCreateParams(IList<object> parameters) : base(parameters) { }
+
+        internal TsCreateParams(long? retentionTime, IReadOnlyCollection<TimeSeriesLabel>? labels, bool? uncompressed,
+            long? chunkSizeBytes, TsDuplicatePolicy? policy)
+        {
+            parameters.AddRetentionTime(retentionTime);
+            parameters.AddChunkSize(chunkSizeBytes);
+            parameters.AddLabels(labels);
+            parameters.AddUncompressed(uncompressed);
+            parameters.AddDuplicatePolicy(policy);
+        }
     }
+
     public class TsAlterParams : TsBaseParams
     {
-        internal TsAlterParams(object[] parameters) : base(parameters) { }
+        internal TsAlterParams(IList<object> parameters) : base(parameters) { }
+
+        internal TsAlterParams(long? retentionTime, long? chunkSizeBytes, TsDuplicatePolicy? policy, IReadOnlyCollection<TimeSeriesLabel>? labels)
+        {
+            parameters.AddRetentionTime(retentionTime);
+            parameters.AddChunkSize(chunkSizeBytes);
+            parameters.AddDuplicatePolicy(policy);
+            parameters.AddLabels(labels);
+        }
     }
 
     public class TsAddParams : TsBaseParams
     {
-        internal TsAddParams(object[] parameters) : base(parameters) { }
+        internal TsAddParams(IList<object> parameters) : base(parameters) { }
+
+        internal TsAddParams(TimeStamp timestamp, double value, long? retentionTime, IReadOnlyCollection<TimeSeriesLabel>? labels, bool? uncompressed, long? chunkSizeBytes, TsDuplicatePolicy? policy)
+        {
+            parameters.Add(timestamp.Value);
+            parameters.Add(value);
+            parameters.AddRetentionTime(retentionTime);
+            parameters.AddChunkSize(chunkSizeBytes);
+            parameters.AddLabels(labels);
+            parameters.AddUncompressed(uncompressed);
+            parameters.AddOnDuplicate(policy);
+        }
     }
 
     public class TsIncrByParams : TsBaseParams
     {
-        internal TsIncrByParams(object[] parameters) : base(parameters) { }
+        internal TsIncrByParams(IList<object> parameters) : base(parameters) { }
+
+        internal TsIncrByParams(double value, TimeStamp? timestampMaybe, long? retentionTime,
+            IReadOnlyCollection<TimeSeriesLabel>? labels, bool? uncompressed, long? chunkSizeBytes)
+        {
+            parameters.Add(value);
+            if (timestampMaybe is { } timestamp) parameters.AddTimeStamp(timestamp);
+            parameters.AddRetentionTime(retentionTime);
+            parameters.AddChunkSize(chunkSizeBytes);
+            if (labels != null) parameters.AddLabels(labels);
+            parameters.AddUncompressed(uncompressed);
+        }
     }
 
-    public class TsDecrByParams : TsBaseParams
+    public class TsDecrByParams : TsIncrByParams
     {
-        internal TsDecrByParams(object[] parameters) : base(parameters) { }
+        internal TsDecrByParams(IList<object> parameters) : base(parameters) { }
+
+        internal TsDecrByParams(double value, TimeStamp? timestampMaybe, long? retentionTime, IReadOnlyCollection<TimeSeriesLabel>? labels, bool? uncompressed, long? chunkSizeBytes)
+            : base(value, timestampMaybe, retentionTime, labels, uncompressed, chunkSizeBytes)
+        { }
     }
+
 }
diff --git a/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs b/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs
index 3f484120..2c7df31c 100644
--- a/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs
+++ b/src/NRedisStack/TimeSeries/Literals/CommandArgs.cs
@@ -23,6 +23,6 @@ internal class TimeSeriesArgs
         public const string DEBUG = "DEBUG";
         public const string BUCKETTIMESTAMP = "BUCKETTIMESTAMP";
         public const string EMPTY = "EMPTY";
-        public const String VALUES = "VALUES";
+        public const String IGNORE = "IGNORE";
     }
 }
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesAux.cs b/src/NRedisStack/TimeSeries/TimeSeriesAux.cs
index 033d9baa..e9c8d870 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesAux.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesAux.cs
@@ -12,54 +12,6 @@ public static void AddLatest(this IList<object> args, bool latest)
             if (latest) args.Add(TimeSeriesArgs.LATEST);
         }
 
-        public static void AddRetentionTime(this IList<object> args, long? retentionTime)
-        {
-            if (retentionTime.HasValue)
-            {
-                args.Add(TimeSeriesArgs.RETENTION);
-                args.Add(retentionTime);
-            }
-        }
-
-        public static void AddChunkSize(this IList<object> args, long? chunkSize)
-        {
-            if (chunkSize.HasValue)
-            {
-                args.Add(TimeSeriesArgs.CHUNK_SIZE);
-                args.Add(chunkSize);
-            }
-        }
-
-        public static void AddLabels(this IList<object> args, IReadOnlyCollection<TimeSeriesLabel>? labels)
-        {
-            if (labels != null)
-            {
-                args.Add(TimeSeriesArgs.LABELS);
-                foreach (var label in labels)
-                {
-                    args.Add(label.Key);
-                    args.Add(label.Value);
-                }
-            }
-        }
-
-        public static void AddUncompressed(this IList<object> args, bool? uncompressed)
-        {
-            if (uncompressed.HasValue)
-            {
-                args.Add(TimeSeriesArgs.UNCOMPRESSED);
-            }
-        }
-        public static void AddIgnoreValues(this IList<object> args, long? ignoreMaxTimeDiff, long? ignoreMaxValDiff)
-        {
-            if (ignoreMaxTimeDiff != null || ignoreMaxValDiff != null)
-            {
-                args.Add(TimeSeriesArgs.VALUES);
-                args.Add(ignoreMaxTimeDiff ?? 0);
-                args.Add(ignoreMaxValDiff ?? 0);
-            }
-        }
-
         public static void AddCount(this IList<object> args, long? count)
         {
             if (count.HasValue)
@@ -69,25 +21,6 @@ public static void AddCount(this IList<object> args, long? count)
             }
         }
 
-        public static void AddDuplicatePolicy(this IList<object> args, TsDuplicatePolicy? policy)
-        {
-            if (policy.HasValue)
-            {
-                args.Add(TimeSeriesArgs.DUPLICATE_POLICY);
-                args.Add(policy.Value.AsArg());
-            }
-        }
-
-
-        public static void AddOnDuplicate(this IList<object> args, TsDuplicatePolicy? policy)
-        {
-            if (policy.HasValue)
-            {
-                args.Add(TimeSeriesArgs.ON_DUPLICATE);
-                args.Add(policy.Value.AsArg());
-            }
-        }
-
         public static void AddAlign(this IList<object> args, TimeStamp? alignMaybe)
         {
             if (alignMaybe is { } align)
@@ -221,53 +154,6 @@ public static void AddRule(this IList<object> args, TimeSeriesRule rule)
             args.Add(rule.TimeBucket);
         }
 
-        public static List<object> BuildTsCreateArgs(string key, long? retentionTime, IReadOnlyCollection<TimeSeriesLabel>? labels, bool? uncompressed,
-            long? chunkSizeBytes, TsDuplicatePolicy? policy)
-        {
-            var args = new List<object> { key };
-            args.AddRetentionTime(retentionTime);
-            args.AddChunkSize(chunkSizeBytes);
-            args.AddLabels(labels);
-            args.AddUncompressed(uncompressed);
-            args.AddDuplicatePolicy(policy);
-            return args;
-        }
-
-        public static List<object> BuildTsAlterArgs(string key, long? retentionTime, long? chunkSizeBytes,
-                                         TsDuplicatePolicy? policy, IReadOnlyCollection<TimeSeriesLabel>? labels)
-        {
-            var args = new List<object> { key };
-            args.AddRetentionTime(retentionTime);
-            args.AddChunkSize(chunkSizeBytes);
-            args.AddDuplicatePolicy(policy);
-            args.AddLabels(labels);
-            return args;
-        }
-
-        public static List<object> BuildTsAddArgs(string key, TimeStamp timestamp, double value, long? retentionTime,
-            IReadOnlyCollection<TimeSeriesLabel>? labels, bool? uncompressed, long? chunkSizeBytes, TsDuplicatePolicy? policy)
-        {
-            var args = new List<object> { key, timestamp.Value, value };
-            args.AddRetentionTime(retentionTime);
-            args.AddChunkSize(chunkSizeBytes);
-            args.AddLabels(labels);
-            args.AddUncompressed(uncompressed);
-            args.AddOnDuplicate(policy);
-            return args;
-        }
-
-        public static List<object> BuildTsIncrDecrByArgs(string key, double value, TimeStamp? timestampMaybe, long? retentionTime,
-            IReadOnlyCollection<TimeSeriesLabel>? labels, bool? uncompressed, long? chunkSizeBytes)
-        {
-            var args = new List<object> { key, value };
-            if (timestampMaybe is { } timestamp) args.AddTimeStamp(timestamp);
-            args.AddRetentionTime(retentionTime);
-            args.AddChunkSize(chunkSizeBytes);
-            if (labels != null) args.AddLabels(labels);
-            args.AddUncompressed(uncompressed);
-            return args;
-        }
-
         public static List<object> BuildTsDelArgs(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp)
         {
             var args = new List<object>
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs
index 3b304b79..09fd4c67 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs
@@ -14,6 +14,7 @@ public TimeSeriesCommands(IDatabase db) : base(db)
         #region Create
 
         /// <inheritdoc/>
+        [Obsolete]
         public bool Create(string key, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.Create(key, retentionTime, labels,
@@ -21,18 +22,25 @@ public bool Create(string key, long? retentionTime = null, IReadOnlyCollection<T
                                                                 duplicatePolicy)).OKtoBoolean();
         }
 
+        /// <inheritdoc/>
+        public bool Create(string key, TsCreateParams parameters) => _db.Execute(TimeSeriesCommandsBuilder.Create(key, parameters)).OKtoBoolean();
+
         #endregion
 
         #region Update
 
         /// <inheritdoc/>
+        [Obsolete]
         public bool Alter(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.Alter(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels)).OKtoBoolean();
         }
 
+        /// <inheritdoc/>
+        public bool Alter(string key, TsAlterParams parameters) => _db.Execute(TimeSeriesCommandsBuilder.Alter(key, parameters)).OKtoBoolean();
 
         /// <inheritdoc/>
+        [Obsolete]
         public TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime = null,
         IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null,
         long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
@@ -41,6 +49,9 @@ public TimeStamp Add(string key, TimeStamp timestamp, double value, long? retent
                                                             uncompressed, chunkSizeBytes, duplicatePolicy)).ToTimeStamp();
         }
 
+        /// <inheritdoc/>
+        public TimeStamp Add(string key, TsAddParams parameters) => _db.Execute(TimeSeriesCommandsBuilder.Add(key, parameters)).ToTimeStamp();
+
         /// <inheritdoc/>
         public IReadOnlyList<TimeStamp> MAdd(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence)
         {
@@ -48,6 +59,7 @@ public IReadOnlyList<TimeStamp> MAdd(IReadOnlyCollection<(string key, TimeStamp
         }
 
         /// <inheritdoc/>
+        [Obsolete]
         public TimeStamp IncrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.IncrBy(key, value, timestamp, retentionTime,
@@ -55,12 +67,19 @@ public TimeStamp IncrBy(string key, double value, TimeStamp? timestamp = null, l
         }
 
         /// <inheritdoc/>
+        public TimeStamp IncrBy(string key, TsIncrByParams parameters) => _db.Execute(TimeSeriesCommandsBuilder.IncrBy(key, parameters)).ToTimeStamp();
+
+        /// <inheritdoc/>
+        [Obsolete]
         public TimeStamp DecrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.DecrBy(key, value, timestamp, retentionTime,
                                                                  labels, uncompressed, chunkSizeBytes)).ToTimeStamp();
         }
 
+        /// <inheritdoc/>
+        public TimeStamp DecrBy(string key, TsDecrByParams parameters) => _db.Execute(TimeSeriesCommandsBuilder.DecrBy(key, parameters)).ToTimeStamp();
+
         /// <inheritdoc/>
         public long Del(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp)
         {
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs
index 3a7e1a4b..97e37089 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs
@@ -21,6 +21,9 @@ public async Task<bool> CreateAsync(string key, long? retentionTime = null, IRea
                                                                            duplicatePolicy))).OKtoBoolean();
         }
 
+        /// <inheritdoc/>
+        public async Task<bool> CreateAsync(string key, TsCreateParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Create(key, parameters))).OKtoBoolean();
+
         #endregion
 
         #region Update
@@ -31,6 +34,9 @@ public async Task<bool> AlterAsync(string key, long? retentionTime = null, long?
             return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Alter(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels))).OKtoBoolean();
         }
 
+        /// <inheritdoc/>
+        public async Task<bool> AlterAsync(string key, TsAlterParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Alter(key, parameters))).OKtoBoolean();
+
         /// <inheritdoc/>
         public async Task<TimeStamp> AddAsync(string key, TimeStamp timestamp, double value, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
         {
@@ -38,6 +44,9 @@ public async Task<TimeStamp> AddAsync(string key, TimeStamp timestamp, double va
                                                                         uncompressed, chunkSizeBytes, duplicatePolicy))).ToTimeStamp();
         }
 
+        /// <inheritdoc/>
+        public async Task<TimeStamp> AddAsync(string key, TsAddParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Add(key, parameters))).ToTimeStamp();
+
         /// <inheritdoc/>
         public async Task<IReadOnlyList<TimeStamp>> MAddAsync(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence)
         {
@@ -51,6 +60,11 @@ public async Task<TimeStamp> IncrByAsync(string key, double value, TimeStamp? ti
                                                                             labels, uncompressed, chunkSizeBytes))).ToTimeStamp();
         }
 
+
+        /// <inheritdoc/>
+        public async Task<TimeStamp> IncrByAsync(string key, TsIncrByParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.IncrBy(key, parameters))).ToTimeStamp();
+
+
         /// <inheritdoc/>
         public async Task<TimeStamp> DecrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
@@ -58,6 +72,9 @@ public async Task<TimeStamp> DecrByAsync(string key, double value, TimeStamp? ti
                                                                             labels, uncompressed, chunkSizeBytes))).ToTimeStamp();
         }
 
+        /// <inheritdoc/>
+        public async Task<TimeStamp> DecrByAsync(string key, TsDecrByParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.DecrBy(key, parameters))).ToTimeStamp();
+
         /// <inheritdoc/>
         public async Task<long> DelAsync(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp)
         {
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
index 4edc8ed3..b792b192 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
@@ -2,50 +2,53 @@
 using NRedisStack.Literals.Enums;
 using NRedisStack.DataTypes;
 using NRedisStack.RedisStackCommands;
+using NetTopologySuite.Index.Bintree;
 
 namespace NRedisStack
 {
-    public static class TimeSeriesCommandsBuilder
+    internal static class TimeSeriesCommandsBuilder
     {
         #region Create
 
+        [Obsolete()]
         public static SerializedCommand Create(string key, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
         {
-            var args = TimeSeriesAux.BuildTsCreateArgs(key, retentionTime, labels, uncompressed, chunkSizeBytes, duplicatePolicy);
-            return new SerializedCommand(TS.CREATE, args);
+            var parameters = new TsCreateParams(retentionTime, labels, uncompressed, chunkSizeBytes, duplicatePolicy);
+            return new SerializedCommand(TS.CREATE, parameters.ToArray(key));
         }
 
-        public static SerializedCommand Create(TsCreateParams parameters)
+        public static SerializedCommand Create(string key, TsCreateParams parameters)
         {
-            return new SerializedCommand(TS.CREATE, parameters.GetAsArray());
+            return new SerializedCommand(TS.CREATE, parameters.ToArray(key));
         }
 
         #endregion
 
         #region Update
-
+        [Obsolete()]
         public static SerializedCommand Alter(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null)
         {
-            var args = TimeSeriesAux.BuildTsAlterArgs(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels);
-            return new SerializedCommand(TS.ALTER, args);
+            var parameters = new TsAlterParams(retentionTime, chunkSizeBytes, duplicatePolicy, labels);
+            return new SerializedCommand(TS.ALTER, parameters.ToArray(key));
         }
 
-        public static SerializedCommand Alter(TsAlterParams parameters)
+        public static SerializedCommand Alter(string key, TsAlterParams parameters)
         {
-            return new SerializedCommand(TS.ALTER, parameters.GetAsArray());
+            return new SerializedCommand(TS.ALTER, parameters.ToArray(key));
         }
 
+        [Obsolete()]
         public static SerializedCommand Add(string key, TimeStamp timestamp, double value, long? retentionTime = null,
         IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null,
         long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
         {
-            var args = TimeSeriesAux.BuildTsAddArgs(key, timestamp, value, retentionTime, labels, uncompressed, chunkSizeBytes, duplicatePolicy);
-            return new SerializedCommand(TS.ADD, args);
+            var parameters = new TsAddParams(timestamp, value, retentionTime, labels, uncompressed, chunkSizeBytes, duplicatePolicy);
+            return new SerializedCommand(TS.ADD, parameters.ToArray(key));
         }
 
-        public static SerializedCommand Add(TsAddParams parameters)
+        public static SerializedCommand Add(string key, TsAddParams parameters)
         {
-            return new SerializedCommand(TS.ADD, parameters.GetAsArray());
+            return new SerializedCommand(TS.ADD, parameters.ToArray(key));
         }
 
         public static SerializedCommand MAdd(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence)
@@ -54,26 +57,28 @@ public static SerializedCommand MAdd(IReadOnlyCollection<(string key, TimeStamp
             return new SerializedCommand(TS.MADD, args);
         }
 
+        [Obsolete()]
         public static SerializedCommand IncrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
-            var args = TimeSeriesAux.BuildTsIncrDecrByArgs(key, value, timestamp, retentionTime, labels, uncompressed, chunkSizeBytes);
-            return new SerializedCommand(TS.INCRBY, args);
+            var parameters = new TsIncrByParams(value, timestamp, retentionTime, labels, uncompressed, chunkSizeBytes);
+            return new SerializedCommand(TS.INCRBY, parameters.ToArray(key));
         }
 
-        public static SerializedCommand IncrBy(TsIncrByParams parameters)
+        public static SerializedCommand IncrBy(string key, TsIncrByParams parameters)
         {
-            return new SerializedCommand(TS.INCRBY, parameters.GetAsArray());
+            return new SerializedCommand(TS.INCRBY, parameters.ToArray(key));
         }
 
+        [Obsolete()]
         public static SerializedCommand DecrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
-            var args = TimeSeriesAux.BuildTsIncrDecrByArgs(key, value, timestamp, retentionTime, labels, uncompressed, chunkSizeBytes);
-            return new SerializedCommand(TS.DECRBY, args);
+            var parameters = new TsDecrByParams(value, timestamp, retentionTime, labels, uncompressed, chunkSizeBytes);
+            return new SerializedCommand(TS.DECRBY, parameters.ToArray(key));
         }
 
-        public static SerializedCommand DecrBy(TsDecrByParams parameters)
+        public static SerializedCommand DecrBy(string key, TsDecrByParams parameters)
         {
-            return new SerializedCommand(TS.DECRBY, parameters.GetAsArray());
+            return new SerializedCommand(TS.DECRBY, parameters.ToArray(key));
         }
 
         public static SerializedCommand Del(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp)
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs b/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
index 8ee97003..0c212337 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
@@ -3,150 +3,245 @@
 using NRedisStack.DataTypes;
 using NRedisStack.RedisStackCommands;
 using System.Collections.ObjectModel;
+using NRedisStack.Extensions;
 
 namespace NRedisStack
 {
 
     public abstract class TsBaseParamsBuilder<T> where T : TsBaseParamsBuilder<T>
     {
-        internal string key;
-        internal long? retentionTime;
-        internal IReadOnlyCollection<TimeSeriesLabel>? labels;
-        internal long? chunkSizeBytes;
-        internal long? ignoreMaxTimeDiff;
-        internal long? ignoreMaxValDiff;
-        internal TsBaseParamsBuilder() { }
+        internal protected long? retentionTime;
+        internal protected IReadOnlyCollection<TimeSeriesLabel>? labels;
+        internal protected long? chunkSizeBytes;
+        internal protected long? ignoreMaxTimeDiff;
+        internal protected long? ignoreMaxValDiff;
 
-        public T addKey(string key)
-        {
-            this.key = key;
-            return (T)this;
-        }
-        public T addRetentionTime(long? retentionTime)
+
+        internal protected double? value;
+        internal protected TimeStamp? timestamp;
+        internal protected bool? uncompressed;
+        internal protected TsDuplicatePolicy? duplicatePolicy;
+
+        internal TsBaseParamsBuilder()
+        { }
+
+        public T AddRetentionTime(long retentionTime)
         {
             this.retentionTime = retentionTime;
             return (T)this;
         }
-        public T addLabels(ReadOnlyCollection<TimeSeriesLabel>? labels)
+        public T AddLabels(ReadOnlyCollection<TimeSeriesLabel> labels)
         {
             this.labels = labels;
             return (T)this;
         }
-        public T addChunkSizeBytes(long? chunkSizeBytes)
+        public T AddChunkSizeBytes(long chunkSizeBytes)
         {
             this.chunkSizeBytes = chunkSizeBytes;
             return (T)this;
         }
 
-        public T addIgnoreMaxTimeDiff(long? ignoreMaxTimeDiff)
+        public T AddIgnoreValues(long ignoreMaxTimeDiff, long ignoreMaxValDiff)
         {
             this.ignoreMaxTimeDiff = ignoreMaxTimeDiff;
+            this.ignoreMaxValDiff = ignoreMaxValDiff;
             return (T)this;
         }
-        public T addIgnoreMaxValDiff(long? ignoreMaxValDiff)
+
+        protected T AddValue(double value)
         {
-            this.ignoreMaxValDiff = ignoreMaxValDiff;
+            this.value = value;
             return (T)this;
         }
+
+        protected T AddTimestamp(TimeStamp timestamp)
+        {
+            this.timestamp = timestamp;
+            return (T)this;
+        }
+
+        protected T AddUncompressed(bool uncompressed)
+        {
+            this.uncompressed = uncompressed;
+            return (T)this;
+        }
+
+        protected T AddDuplicatePolicy(TsDuplicatePolicy duplicatePolicy)
+        {
+            this.duplicatePolicy = duplicatePolicy;
+            return (T)this;
+        }
+
+    }
+
+    public static class TsParamsHelper
+    {
+        public static void AddRetentionTime(this IList<object> args, long? retentionTime)
+        {
+            if (retentionTime.HasValue)
+            {
+                args.Add(TimeSeriesArgs.RETENTION);
+                args.Add(retentionTime);
+            }
+        }
+
+        public static void AddChunkSize(this IList<object> args, long? chunkSize)
+        {
+            if (chunkSize.HasValue)
+            {
+                args.Add(TimeSeriesArgs.CHUNK_SIZE);
+                args.Add(chunkSize);
+            }
+        }
+
+        public static void AddLabels(this IList<object> args, IReadOnlyCollection<TimeSeriesLabel>? labels)
+        {
+            if (labels != null)
+            {
+                args.Add(TimeSeriesArgs.LABELS);
+                foreach (var label in labels)
+                {
+                    args.Add(label.Key);
+                    args.Add(label.Value);
+                }
+            }
+        }
+
+        public static void AddUncompressed(this IList<object> args, bool? uncompressed)
+        {
+            if (uncompressed.HasValue)
+            {
+                args.Add(TimeSeriesArgs.UNCOMPRESSED);
+            }
+        }
+
+        public static void AddIgnoreValues(this IList<object> args, long? ignoreMaxTimeDiff, long? ignoreMaxValDiff)
+        {
+            if (ignoreMaxTimeDiff != null || ignoreMaxValDiff != null)
+            {
+                args.Add(TimeSeriesArgs.IGNORE);
+                args.Add(ignoreMaxTimeDiff ?? 0);
+                args.Add(ignoreMaxValDiff ?? 0);
+            }
+        }
+
+        public static void AddDuplicatePolicy(this IList<object> args, TsDuplicatePolicy? policy)
+        {
+            if (policy.HasValue)
+            {
+                args.Add(TimeSeriesArgs.DUPLICATE_POLICY);
+                args.Add(policy.Value.AsArg());
+            }
+        }
+
+        public static void AddOnDuplicate(this IList<object> args, TsDuplicatePolicy? policy)
+        {
+            if (policy.HasValue)
+            {
+                args.Add(TimeSeriesArgs.ON_DUPLICATE);
+                args.Add(policy.Value.AsArg());
+            }
+        }
     }
 
     public class TsCreateParamsBuilder : TsBaseParamsBuilder<TsCreateParamsBuilder>
     {
-        private bool? uncompressed;
-        private TsDuplicatePolicy? duplicatePolicy;
         public TsCreateParams build()
         {
-            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
-
-            var args = new List<object> { key };
+            var args = new List<object>();
             args.AddRetentionTime(retentionTime);
             args.AddChunkSize(chunkSizeBytes);
             args.AddLabels(labels);
             args.AddUncompressed(uncompressed);
             args.AddDuplicatePolicy(duplicatePolicy);
             args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
-            return new TsCreateParams(args.ToArray());
+            return new TsCreateParams(args);
         }
+
+        public TsCreateParamsBuilder AddUncompressed(bool uncompressed) => base.AddUncompressed(uncompressed);
+        public TsCreateParamsBuilder AddDuplicatePolicy(TsDuplicatePolicy duplicatePolicy) => base.AddDuplicatePolicy(duplicatePolicy);
+
     }
 
     public class TsAlterParamsBuilder : TsBaseParamsBuilder<TsAlterParamsBuilder>
     {
-        private TsDuplicatePolicy? duplicatePolicy;
         public TsAlterParams build()
         {
-            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
-
-            var args = new List<object> { key };
+            var args = new List<object>();
             args.AddRetentionTime(retentionTime);
             args.AddChunkSize(chunkSizeBytes);
             args.AddDuplicatePolicy(duplicatePolicy);
             args.AddLabels(labels);
             args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
-            return new TsAlterParams(args.ToArray());
+            return new TsAlterParams(args);
         }
+
+        public TsAlterParamsBuilder AddDuplicatePolicy(TsDuplicatePolicy duplicatePolicy) => base.AddDuplicatePolicy(duplicatePolicy);
     }
 
     public class TsAddParamsBuilder : TsBaseParamsBuilder<TsAddParamsBuilder>
     {
-        private double value;
-        private TimeStamp timestamp;
-        private bool? uncompressed;
-        private TsDuplicatePolicy? duplicatePolicy;
         public TsAddParams build()
         {
-            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+            if (timestamp == null) throw new NotSupportedException("Operation without 'timestamp' is not supported!");
+            if (value == null) throw new NotSupportedException("Operation without 'value' is not supported!");
 
-            var args = new List<object> { key, timestamp.Value, value };
+            var args = new List<object> { timestamp.Value.Value, value };
             args.AddRetentionTime(retentionTime);
             args.AddChunkSize(chunkSizeBytes);
             args.AddLabels(labels);
             args.AddUncompressed(uncompressed);
             args.AddOnDuplicate(duplicatePolicy);
             args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
-            return new TsAddParams(args.ToArray());
+            return new TsAddParams(args);
         }
+
+        public TsAddParamsBuilder AddValue(double value) => base.AddValue(value);
+        public TsAddParamsBuilder AddTimestamp(TimeStamp timestamp) => base.AddTimestamp(timestamp);
+        public TsAddParamsBuilder AddUncompressed(bool uncompressed) => base.AddUncompressed(uncompressed);
+        public TsAddParamsBuilder AddOnDuplicate(TsDuplicatePolicy duplicatePolicy) => base.AddDuplicatePolicy(duplicatePolicy);
     }
 
     public class TsIncrByParamsBuilder : TsBaseParamsBuilder<TsIncrByParamsBuilder>
     {
-        private double value;
-        private TimeStamp? timestamp;
-        private bool? uncompressed;
-        private TsDuplicatePolicy? duplicatePolicy;
-
         public TsIncrByParams build()
         {
-            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+            if (value == null) throw new NotSupportedException("Operation without 'value' is not supported!");
 
-            var args = new List<object> { key, value };
+            var args = new List<object> { value };
             if (timestamp != null) args.AddTimeStamp(timestamp.Value);
             args.AddRetentionTime(retentionTime);
             args.AddChunkSize(chunkSizeBytes);
             if (labels != null) args.AddLabels(labels);
             args.AddUncompressed(uncompressed);
             args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
-            return new TsIncrByParams(args.ToArray());
+            return new TsIncrByParams(args);
         }
+
+        public TsIncrByParamsBuilder AddValue(double value) => base.AddValue(value);
+        public TsIncrByParamsBuilder AddTimestamp(TimeStamp timestamp) => base.AddTimestamp(timestamp);
+        public TsIncrByParamsBuilder AddUncompressed(bool uncompressed) => base.AddUncompressed(uncompressed);
+        public TsIncrByParamsBuilder AddDuplicatePolicy(TsDuplicatePolicy duplicatePolicy) => base.AddDuplicatePolicy(duplicatePolicy);
     }
 
     public class TsDecrByParamsBuilder : TsBaseParamsBuilder<TsDecrByParamsBuilder>
     {
-        private double value;
-        private TimeStamp? timestamp;
-        private bool? uncompressed;
         public TsDecrByParams build()
         {
-            if (String.IsNullOrWhiteSpace(key)) throw new NotSupportedException("Operation without a key is not supported!");
+            if (value == null) throw new NotSupportedException("Operation without 'value' is not supported!");
 
-            var args = new List<object> { key, value };
+            var args = new List<object> { value };
             if (timestamp != null) args.AddTimeStamp(timestamp.Value);
             args.AddRetentionTime(retentionTime);
             args.AddChunkSize(chunkSizeBytes);
             if (labels != null) args.AddLabels(labels);
             args.AddUncompressed(uncompressed);
             args.AddIgnoreValues(ignoreMaxTimeDiff, ignoreMaxValDiff);
-            return new TsDecrByParams(args.ToArray());
+            return new TsDecrByParams(args);
         }
+        public TsDecrByParamsBuilder AddValue(double value) => base.AddValue(value);
+        public TsDecrByParamsBuilder AddTimestamp(TimeStamp timestamp) => base.AddTimestamp(timestamp);
+        public TsDecrByParamsBuilder AddUncompressed(bool uncompressed) => base.AddUncompressed(uncompressed);
+        public TsDecrByParamsBuilder AddDuplicatePolicy(TsDuplicatePolicy duplicatePolicy) => base.AddDuplicatePolicy(duplicatePolicy);
     }
-
 }
\ No newline at end of file
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs
index 804eda42..9df3e453 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs
@@ -229,5 +229,24 @@ public void TestWrongParameters()
             ex = Assert.Throws<RedisServerException>(() => ts.Add(key, "-", value));
             Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
         }
+
+        [Fact]
+        public void TestAddAndIgnoreValues()
+        {
+            IDatabase db = redisFixture.Redis.GetDatabase();
+            db.Execute("FLUSHALL");
+            var ts = db.TS();
+            var parameters = new TsAddParamsBuilder().AddTimestamp(101).AddValue(102).AddIgnoreValues(15, 16).build();
+            ts.Add(key, parameters);
+
+            int j = -1, k = -1;
+            RedisResult info = TimeSeriesHelper.getInfo(db, key, out j, out k);
+            Assert.NotNull(info);
+            Assert.True(info.Length > 0);
+            Assert.NotEqual(j, -1);
+            Assert.NotEqual(k, -1);
+            Assert.Equal(15, (long)info[j + 1]);
+            Assert.Equal(16, (long)info[k + 1]);
+        }
     }
 }
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs
index 281518b4..fe3d18db 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs
@@ -59,5 +59,25 @@ public void TestAlterPolicyAndChunk()
             Assert.Equal(128, info.ChunkSize);
             Assert.Equal(TsDuplicatePolicy.MIN, info.DuplicatePolicy);
         }
+
+        [Fact]
+        public void TestAlterAndIgnoreValues()
+        {
+            IDatabase db = redisFixture.Redis.GetDatabase();
+            db.Execute("FLUSHALL");
+            var ts = db.TS();
+            ts.Create(key, new TsCreateParamsBuilder().build());
+            var parameters = new TsAlterParamsBuilder().AddIgnoreValues(13, 14).build();
+            Assert.True(ts.Alter(key, parameters));
+
+            int j = -1, k = -1;
+            RedisResult info = TimeSeriesHelper.getInfo(db, key, out j, out k);
+            Assert.NotNull(info);
+            Assert.True(info.Length > 0);
+            Assert.NotEqual(j, -1);
+            Assert.NotEqual(k, -1);
+            Assert.Equal(13, (long)info[j + 1]);
+            Assert.Equal(14, (long)info[k + 1]);
+        }
     }
 }
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs
index 317235af..57a2199f 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs
@@ -3,6 +3,7 @@
 using NRedisStack.RedisStackCommands;
 using NRedisStack.Literals.Enums;
 using Xunit;
+using System.Runtime.CompilerServices;
 
 namespace NRedisStack.Tests.TimeSeries.TestAPI
 {
@@ -117,5 +118,23 @@ public void TestCreatehDuplicatePolicySum()
             var ts = db.TS();
             Assert.True(ts.Create(key, duplicatePolicy: TsDuplicatePolicy.SUM));
         }
+
+        [Fact]
+        public void TestCreateAndIgnoreValues()
+        {
+            IDatabase db = redisFixture.Redis.GetDatabase();
+            db.Execute("FLUSHALL");
+            var ts = db.TS();
+            var parameters = new TsCreateParamsBuilder().AddIgnoreValues(11, 12).build();
+            Assert.True(ts.Create(key, parameters));
+
+            int j = -1, k = -1;
+            RedisResult info = TimeSeriesHelper.getInfo(db, key, out j, out k);
+
+            Assert.NotEqual(j, -1);
+            Assert.NotEqual(k, -1);
+            Assert.Equal(11, (long)info[j + 1]);
+            Assert.Equal(12, (long)info[k + 1]);
+        }
     }
 }
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs
index 14e54e6c..64735701 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs
@@ -100,5 +100,24 @@ public void TestWrongParameters()
             ex = Assert.Throws<RedisServerException>(() => ts.DecrBy(key, value, timestamp: "-"));
             Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
         }
+
+        [Fact]
+        public async void TestIncrDecryByAndIgnoreValues()
+        {
+            IDatabase db = redisFixture.Redis.GetDatabase();
+            db.Execute("FLUSHALL");
+            var ts = db.TS();
+            var decrParameters = new TsDecrByParamsBuilder().AddValue(1).AddIgnoreValues(15, 16).build();
+            ts.DecrBy(key, decrParameters);
+
+            int j = -1, k = -1;
+            RedisResult info = TimeSeriesHelper.getInfo(db, key, out j, out k);
+            Assert.NotNull(info);
+            Assert.True(info.Length > 0);
+            Assert.NotEqual(j, -1);
+            Assert.NotEqual(k, -1);
+            Assert.Equal(15, (long)info[j + 1]);
+            Assert.Equal(16, (long)info[k + 1]);
+        }
     }
 }
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs
index af1d35bf..bbff0649 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs
@@ -100,5 +100,24 @@ public void TestWrongParameters()
             ex = Assert.Throws<RedisServerException>(() => ts.IncrBy(key, value, timestamp: "-"));
             Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
         }
+
+        [Fact]
+        public async void TestIncrByAndIgnoreValues()
+        {
+            IDatabase db = redisFixture.Redis.GetDatabase();
+            db.Execute("FLUSHALL");
+            var ts = db.TS();
+            var incrParameters = new TsIncrByParamsBuilder().AddValue(1).AddIgnoreValues(15, 16).build();
+            ts.IncrBy(key, incrParameters);
+
+            int j = -1, k = -1;
+            RedisResult info = TimeSeriesHelper.getInfo(db, key, out j, out k);
+            Assert.NotNull(info);
+            Assert.True(info.Length > 0);
+            Assert.NotEqual(j, -1);
+            Assert.NotEqual(k, -1);
+            Assert.Equal(15, (long)info[j + 1]);
+            Assert.Equal(16, (long)info[k + 1]);
+        }
     }
 }
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs
new file mode 100644
index 00000000..eefc46a0
--- /dev/null
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs
@@ -0,0 +1,25 @@
+using StackExchange.Redis;
+using NRedisStack.DataTypes;
+using NRedisStack.RedisStackCommands;
+using NRedisStack.Literals.Enums;
+using Xunit;
+namespace NRedisStack.Tests.TimeSeries.TestAPI
+{
+    public class TimeSeriesHelper
+    {
+        public static RedisResult getInfo(IDatabase db, string key, out int j, out int k)
+        {
+            var cmd = new SerializedCommand("TS.INFO", key);
+            RedisResult info = db.Execute(cmd);
+
+            j = -1;
+            k = -1;
+            for (int i = 0; i < info.Length; i++)
+            {
+                if (info[i].ToString().Equals("ignoreMaxTimeDiff")) j = i;
+                if (info[i].ToString().Equals("ignoreMaxValDiff")) k = i;
+            }
+            return info;
+        }
+    }
+}

From a5d0d58893da52fa7ed2cb6b8f15292f3fa64bc8 Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Tue, 28 May 2024 11:18:45 +0300
Subject: [PATCH 08/13] adding some missing obsolete

---
 src/NRedisStack/TimeSeries/TimeSeriesCommands.cs      | 10 +++++-----
 src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs |  5 +++++
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs
index 09fd4c67..4f759524 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs
@@ -14,7 +14,7 @@ public TimeSeriesCommands(IDatabase db) : base(db)
         #region Create
 
         /// <inheritdoc/>
-        [Obsolete]
+        [Obsolete("Please use the other method with TsCreateParams and check related builder TsCreateParamsBuilder to build parameters.")]
         public bool Create(string key, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.Create(key, retentionTime, labels,
@@ -30,7 +30,7 @@ public bool Create(string key, long? retentionTime = null, IReadOnlyCollection<T
         #region Update
 
         /// <inheritdoc/>
-        [Obsolete]
+        [Obsolete("Please use the other method with TsAlterParams and check related builder TsAlterParamsBuilder to build parameters.")]
         public bool Alter(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.Alter(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels)).OKtoBoolean();
@@ -40,7 +40,7 @@ public bool Alter(string key, long? retentionTime = null, long? chunkSizeBytes =
         public bool Alter(string key, TsAlterParams parameters) => _db.Execute(TimeSeriesCommandsBuilder.Alter(key, parameters)).OKtoBoolean();
 
         /// <inheritdoc/>
-        [Obsolete]
+        [Obsolete("Please use the other method with TsAddParams and check related builder TsAddParamsBuilder to build parameters.")]
         public TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime = null,
         IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null,
         long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
@@ -59,7 +59,7 @@ public IReadOnlyList<TimeStamp> MAdd(IReadOnlyCollection<(string key, TimeStamp
         }
 
         /// <inheritdoc/>
-        [Obsolete]
+        [Obsolete("Please use the other method with TsIncrByParams and check related builder TsIncryByParamsBuilder to build parameters.")]
         public TimeStamp IncrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.IncrBy(key, value, timestamp, retentionTime,
@@ -70,7 +70,7 @@ public TimeStamp IncrBy(string key, double value, TimeStamp? timestamp = null, l
         public TimeStamp IncrBy(string key, TsIncrByParams parameters) => _db.Execute(TimeSeriesCommandsBuilder.IncrBy(key, parameters)).ToTimeStamp();
 
         /// <inheritdoc/>
-        [Obsolete]
+        [Obsolete("Please use the other method with TsDecrByParams and check related builder TsDecryByParamsBuilder to build parameters.")]
         public TimeStamp DecrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null)
         {
             return _db.Execute(TimeSeriesCommandsBuilder.DecrBy(key, value, timestamp, retentionTime,
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs
index 97e37089..a6486f48 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs
@@ -14,6 +14,7 @@ public TimeSeriesCommandsAsync(IDatabaseAsync db)
         #region Create
 
         /// <inheritdoc/>
+        [Obsolete("Please use the other method with TsCreateParams and check related builder TsCreateParamsBuilder to build parameters.")]
         public async Task<bool> CreateAsync(string key, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
         {
             return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Create(key, retentionTime, labels,
@@ -29,6 +30,7 @@ public async Task<bool> CreateAsync(string key, long? retentionTime = null, IRea
         #region Update
 
         /// <inheritdoc/>
+        [Obsolete("Please use the other method with TsAlterParams and check related builder TsAlterParamsBuilder to build parameters.")]
         public async Task<bool> AlterAsync(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null)
         {
             return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Alter(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels))).OKtoBoolean();
@@ -38,6 +40,7 @@ public async Task<bool> AlterAsync(string key, long? retentionTime = null, long?
         public async Task<bool> AlterAsync(string key, TsAlterParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Alter(key, parameters))).OKtoBoolean();
 
         /// <inheritdoc/>
+        [Obsolete("Please use the other method with TsAddParams and check related builder TsAddParamsBuilder to build parameters.")]
         public async Task<TimeStamp> AddAsync(string key, TimeStamp timestamp, double value, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel>? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
         {
             return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Add(key, timestamp, value, retentionTime, labels,
@@ -62,6 +65,7 @@ public async Task<TimeStamp> IncrByAsync(string key, double value, TimeStamp? ti
 
 
         /// <inheritdoc/>
+        [Obsolete("Please use the other method with TsIncrByParams and check related builder TsIncryByParamsBuilder to build parameters.")]
         public async Task<TimeStamp> IncrByAsync(string key, TsIncrByParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.IncrBy(key, parameters))).ToTimeStamp();
 
 
@@ -73,6 +77,7 @@ public async Task<TimeStamp> DecrByAsync(string key, double value, TimeStamp? ti
         }
 
         /// <inheritdoc/>
+        [Obsolete("Please use the other method with TsDecrByParams and check related builder TsDecryByParamsBuilder to build parameters.")]
         public async Task<TimeStamp> DecrByAsync(string key, TsDecrByParams parameters) => (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.DecrBy(key, parameters))).ToTimeStamp();
 
         /// <inheritdoc/>

From b6700af2bc22728c5ff02bf762cfcf5b18adbe6e Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Tue, 28 May 2024 11:40:24 +0300
Subject: [PATCH 09/13] undo CI related commits

---
 .github/workflows/integration.yml                   | 4 ++--
 .github/workflows/modes/.env.enterprise_oss_cluster | 3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index 73eeed82..e289efdc 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -6,7 +6,7 @@ on:
       - 'docs/**'
       - '**/*.md'
     branches:
-      - ali/ClusterSupport2-p1
+      - master
   pull_request:
   schedule:
     - cron: "0 1 * * *"
@@ -177,4 +177,4 @@ jobs:
         shell: cmd
         run: |
           START wsl ./redis-stack-server-${{env.redis_stack_version}}/bin/redis-stack-server &
-          dotnet test -f net481 --no-build --verbosity detailed
+          dotnet test -f net481 --no-build --verbosity detailed
\ No newline at end of file
diff --git a/.github/workflows/modes/.env.enterprise_oss_cluster b/.github/workflows/modes/.env.enterprise_oss_cluster
index d8bb8ddd..1b45122d 100644
--- a/.github/workflows/modes/.env.enterprise_oss_cluster
+++ b/.github/workflows/modes/.env.enterprise_oss_cluster
@@ -6,6 +6,3 @@ RE_PASS=12345
 RE_CLUSTER_NAME=test
 RE_USE_OSS_CLUSTER=true
 RE_DB_PORT=6378
-oss_cluster=true
-oss_cluster_api_preferred_ip_type=external
-oss_cluster_api_preferred_endpoint_type=hostname

From 6850b9aac1a91d654ce10ece403a72a9d34707db Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Tue, 28 May 2024 11:41:27 +0300
Subject: [PATCH 10/13] undo CI related commits

---
 .github/workflows/integration.yml                   | 2 --
 .github/workflows/modes/.env.enterprise_oss_cluster | 2 +-
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml
index e289efdc..de05bcc0 100644
--- a/.github/workflows/integration.yml
+++ b/.github/workflows/integration.yml
@@ -10,7 +10,6 @@ on:
   pull_request:
   schedule:
     - cron: "0 1 * * *"
-  workflow_dispatch:
 
 concurrency:
   group: ${{ github.event.pull_request.number || github.ref }}-integration
@@ -149,7 +148,6 @@ jobs:
       USER_NAME: ${{ secrets.USER_NAME }}
       PASSWORD: ${{ secrets.PASSWORD }}
       ENDPOINT: ${{ secrets.ENDPOINT }}
-      
     steps:
       - uses: actions/checkout@v3
       - uses: Vampire/setup-wsl@v2
diff --git a/.github/workflows/modes/.env.enterprise_oss_cluster b/.github/workflows/modes/.env.enterprise_oss_cluster
index 1b45122d..1b81f571 100644
--- a/.github/workflows/modes/.env.enterprise_oss_cluster
+++ b/.github/workflows/modes/.env.enterprise_oss_cluster
@@ -5,4 +5,4 @@ RE_USERNAME=test@test.com
 RE_PASS=12345
 RE_CLUSTER_NAME=test
 RE_USE_OSS_CLUSTER=true
-RE_DB_PORT=6378
+RE_DB_PORT=6378
\ No newline at end of file

From faa8a7dc95075ac2417d2d5083749a93b3fd6783 Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Tue, 28 May 2024 11:44:24 +0300
Subject: [PATCH 11/13] remove unused import

---
 src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs       | 1 -
 .../NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs  | 4 +---
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
index b792b192..dcd9fcb4 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
@@ -2,7 +2,6 @@
 using NRedisStack.Literals.Enums;
 using NRedisStack.DataTypes;
 using NRedisStack.RedisStackCommands;
-using NetTopologySuite.Index.Bintree;
 
 namespace NRedisStack
 {
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs
index eefc46a0..4cef7208 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TimeSeriesHelper.cs
@@ -1,8 +1,6 @@
 using StackExchange.Redis;
-using NRedisStack.DataTypes;
 using NRedisStack.RedisStackCommands;
-using NRedisStack.Literals.Enums;
-using Xunit;
+
 namespace NRedisStack.Tests.TimeSeries.TestAPI
 {
     public class TimeSeriesHelper

From edec43a6c5c27b48bf9d8fd39ac38b57cc6460be Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Tue, 28 May 2024 11:47:58 +0300
Subject: [PATCH 12/13] remove unused import and make tscommandbuilder public

---
 src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs | 2 +-
 src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs   | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
index dcd9fcb4..b26d3a13 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesCommandsBuilder.cs
@@ -5,7 +5,7 @@
 
 namespace NRedisStack
 {
-    internal static class TimeSeriesCommandsBuilder
+    public static class TimeSeriesCommandsBuilder
     {
         #region Create
 
diff --git a/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs b/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
index 0c212337..c9345d04 100644
--- a/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
+++ b/src/NRedisStack/TimeSeries/TimeSeriesParamsBuilder.cs
@@ -1,7 +1,6 @@
 using NRedisStack.Literals;
 using NRedisStack.Literals.Enums;
 using NRedisStack.DataTypes;
-using NRedisStack.RedisStackCommands;
 using System.Collections.ObjectModel;
 using NRedisStack.Extensions;
 

From 961258a18ba4b49f0435456b272c344ccc6bb15d Mon Sep 17 00:00:00 2001
From: atakavci <a_takavci@yahoo.com>
Date: Fri, 31 May 2024 15:36:08 +0300
Subject: [PATCH 13/13] add version checks for tests

---
 tests/NRedisStack.Tests/Search/SearchTests.cs            | 2 +-
 tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs    | 2 +-
 tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs  | 2 +-
 tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs | 2 +-
 tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs | 2 +-
 tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/tests/NRedisStack.Tests/Search/SearchTests.cs b/tests/NRedisStack.Tests/Search/SearchTests.cs
index 0376a54c..86ae7304 100644
--- a/tests/NRedisStack.Tests/Search/SearchTests.cs
+++ b/tests/NRedisStack.Tests/Search/SearchTests.cs
@@ -702,7 +702,7 @@ public void AlterAdd()
         IDatabase db = redisFixture.Redis.GetDatabase();
         db.Execute("FLUSHALL");
         var ft = db.FT();
-        Schema sc = new Schema().AddTextField("title", 1.0);
+        Schema sc = new Schema().AddTextField("title", 1.0, sortable: true, unf: true);
 
         Assert.True(ft.Create(index, FTCreateParams.CreateParams(), sc));
 
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs
index 9df3e453..a7f40554 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAdd.cs
@@ -230,7 +230,7 @@ public void TestWrongParameters()
             Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
         }
 
-        [Fact]
+        [SkipIfRedis(Comparison.LessThan, "7.4.0")]
         public void TestAddAndIgnoreValues()
         {
             IDatabase db = redisFixture.Redis.GetDatabase();
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs
index fe3d18db..befd8b98 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestAlter.cs
@@ -60,7 +60,7 @@ public void TestAlterPolicyAndChunk()
             Assert.Equal(TsDuplicatePolicy.MIN, info.DuplicatePolicy);
         }
 
-        [Fact]
+        [SkipIfRedis(Comparison.LessThan, "7.4.0")]
         public void TestAlterAndIgnoreValues()
         {
             IDatabase db = redisFixture.Redis.GetDatabase();
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs
index 57a2199f..69a9c263 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestCreate.cs
@@ -119,7 +119,7 @@ public void TestCreatehDuplicatePolicySum()
             Assert.True(ts.Create(key, duplicatePolicy: TsDuplicatePolicy.SUM));
         }
 
-        [Fact]
+        [SkipIfRedis(Comparison.LessThan, "7.4.0")]
         public void TestCreateAndIgnoreValues()
         {
             IDatabase db = redisFixture.Redis.GetDatabase();
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs
index 64735701..52d516c7 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDecrBy.cs
@@ -101,7 +101,7 @@ public void TestWrongParameters()
             Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
         }
 
-        [Fact]
+        [SkipIfRedis(Comparison.LessThan, "7.4.0")]
         public async void TestIncrDecryByAndIgnoreValues()
         {
             IDatabase db = redisFixture.Redis.GetDatabase();
diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs
index bbff0649..2b6bc8c7 100644
--- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs
+++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestIncrBy.cs
@@ -101,7 +101,7 @@ public void TestWrongParameters()
             Assert.Equal("ERR TSDB: invalid timestamp", ex.Message);
         }
 
-        [Fact]
+        [SkipIfRedis(Comparison.LessThan, "7.4.0")]
         public async void TestIncrByAndIgnoreValues()
         {
             IDatabase db = redisFixture.Redis.GetDatabase();