Repository: redis/go-redis

Issue:
Feature: Batch processing cmds in pipeline
Hello everyone.
Thank you very much for adding Cmds() - the ability to retrieve cmds currently in the pipeline.
I'm wondering, are there any plans to support adding multiple commands at once ? At the moment it's only possible to add a single cmd to the pipeline.

Right now our code looks like this:

```go
for _, cmd := range redisPipe.Cmds() {
    txw.parentTx.redisPipe.Process(cmd)
}
```

So essentially we're just iterating over each value in the loop, while inside `.Process` it's simply appending the element to a slice:

```go
func (c *Pipeline) Process(ctx context.Context, cmd Cmder) error {
    c.cmds = append(c.cmds, cmd)
    return nil
}
```

This naturally raises the question - would it be possible to provide a new method for the `Pipeline` structure, for example, `ProcessBatch`:

```go
func (c *Pipeline) ProcessBatch(ctx context.Context, cmds ...Cmder) error {
    c.cmds = append(c.cmds, cmds...)
    return nil
}
```

Or, perhaps in some major version, consider replacing the `cmd Cmder` param in the `Process` method with a variadic version ?

Hints from issue comments:
@htemelski-oss: It makes sense to me to add a `ProcessBatch` method to the pipeline. @ndyakov do you have any concerns?@ndyakov: I can see the benefit of having `ProcessBatch`, but let's not change the `Process` API. Extending is fine as we are just adding this as a feature and not breaking the API. 

Solution patch:
diff --git a/pipeline.go b/pipeline.go
index dbbced5..567bf12 100644
--- a/pipeline.go
+++ b/pipeline.go
@@ -30,9 +30,12 @@ type Pipeliner interface {
 	// If a certain Redis command is not yet supported, you can use Do to execute it.
 	Do(ctx context.Context, args ...interface{}) *Cmd
 
-	// Process puts the commands to be executed into the pipeline buffer.
+	// Process queues the cmd for later execution.
 	Process(ctx context.Context, cmd Cmder) error
 
+	// BatchProcess adds multiple commands to be executed into the pipeline buffer.
+	BatchProcess(ctx context.Context, cmd ...Cmder) error
+
 	// Discard discards all commands in the pipeline buffer that have not yet been executed.
 	Discard()
 
@@ -79,7 +82,12 @@ func (c *Pipeline) Do(ctx context.Context, args ...interface{}) *Cmd {
 
 // Process queues the cmd for later execution.
 func (c *Pipeline) Process(ctx context.Context, cmd Cmder) error {
-	c.cmds = append(c.cmds, cmd)
+	return c.BatchProcess(ctx, cmd)
+}
+
+// BatchProcess queues multiple cmds for later execution.
+func (c *Pipeline) BatchProcess(ctx context.Context, cmd ...Cmder) error {
+	c.cmds = append(c.cmds, cmd...)
 	return nil
 }
 



Test patch:
diff --git a/pipeline_test.go b/pipeline_test.go
index d32ab35..15eacb3 100644
--- a/pipeline_test.go
+++ b/pipeline_test.go
@@ -114,6 +114,25 @@ var _ = Describe("pipelining", func() {
 			err := pipe.Do(ctx).Err()
 			Expect(err).To(Equal(errors.New("redis: please enter the command to be executed")))
 		})
+
+		It("should process", func() {
+			err := pipe.Process(ctx, redis.NewCmd(ctx, "asking"))
+			Expect(err).To(BeNil())
+			Expect(pipe.Cmds()).To(HaveLen(1))
+		})
+
+		It("should batchProcess", func() {
+			err := pipe.BatchProcess(ctx, redis.NewCmd(ctx, "asking"))
+			Expect(err).To(BeNil())
+			Expect(pipe.Cmds()).To(HaveLen(1))
+
+			pipe.Discard()
+			Expect(pipe.Cmds()).To(HaveLen(0))
+
+			err = pipe.BatchProcess(ctx, redis.NewCmd(ctx, "asking"), redis.NewCmd(ctx, "set", "key", "value"))
+			Expect(err).To(BeNil())
+			Expect(pipe.Cmds()).To(HaveLen(2))
+		})
 	}
 
 	Describe("Pipeline", func() {