Repository: meilisearch/meilisearch-go

Issue:
[v1.16] Add support for `/export` API
This issue follows the changes related to Meilisearch v1.16.0 [mega issue](https://github.com/meilisearch/integration-guides/issues/317).

## Description

Add the necessary methods to interact with the [export API](https://www.meilisearch.com/docs/reference/api/export).

For more context, see the related issue in Meilisearch: https://github.com/meilisearch/meilisearch/issues/5713

## Tasks

- [ ] Add the new methods to interact with the Meilisearch API
- [ ] Add new tests cases
- [ ] Write an example code in `.code-samples.meilisearch.yaml` under the `export_post_1` key

Discussion:

Solution patch:
diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml
index 5beaa05..1258752 100644
--- a/.code-samples.meilisearch.yaml
+++ b/.code-samples.meilisearch.yaml
@@ -985,3 +985,21 @@ get_all_batches_1: |-
   client.GetBatches();
 get_batch_1: |-
   client.GetBatch(BATCH_UID);
+export_1: |-
+  client.Export(&meilisearch.ExportParams{
+    URL: URL,
+    APIKey: API_KEY,
+    PayloadSize: "100MB",
+  });
+export_2: |-
+  client.Export(&meilisearch.ExportParams{
+    URL: URL,
+    APIKey: API_KEY,
+    PayloadSize: "50MB",
+    Indexes: map[string]meilisearch.IndexExportOptions{
+    indexUID: {
+      Filter: filter,
+      OverrideSettings: true,
+      }
+    }
+  });
diff --git a/enum.go b/enum.go
index 85ff067..6a662fd 100644
--- a/enum.go
+++ b/enum.go
@@ -75,6 +75,8 @@ const (
 	TaskTypeTaskDeletion TaskType = "taskDeletion"
 	// TaskTypeSnapshotCreation represents a snapshot creation
 	TaskTypeSnapshotCreation TaskType = "snapshotCreation"
+	// TaskTypeExport represents a task exportation
+	TaskTypeExport TaskType = "export"
 )
 
 type (
diff --git a/meilisearch.go b/meilisearch.go
index 19faf96..36860f2 100644
--- a/meilisearch.go
+++ b/meilisearch.go
@@ -733,6 +733,28 @@ func (m *meilisearch) GetBatchWithContext(ctx context.Context, batchUID int) (*B
 	return resp, nil
 }
 
+func (m *meilisearch) Export(param *ExportParams) (*TaskInfo, error) {
+	return m.ExportWithContext(context.Background(), param)
+}
+
+func (m *meilisearch) ExportWithContext(ctx context.Context, param *ExportParams) (*TaskInfo, error) {
+	resp := new(TaskInfo)
+	req := &internalRequest{
+		endpoint:            "/export",
+		method:              http.MethodPost,
+		withRequest:         param,
+		contentType:         contentTypeJSON,
+		withResponse:        resp,
+		withQueryParams:     map[string]string{},
+		acceptedStatusCodes: []int{http.StatusOK, http.StatusAccepted},
+		functionName:        "Export",
+	}
+	if err := m.client.executeRequest(ctx, req); err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
 func getTask(ctx context.Context, cli *client, taskUID int64) (*Task, error) {
 	resp := new(Task)
 	req := &internalRequest{
diff --git a/meilisearch_interface.go b/meilisearch_interface.go
index c32eedd..6fdab60 100644
--- a/meilisearch_interface.go
+++ b/meilisearch_interface.go
@@ -54,6 +54,12 @@ type ServiceManager interface {
 	// ExperimentalFeatures returns the experimental features manager.
 	ExperimentalFeatures() *ExperimentalFeatures
 
+	// Export transfers data from your origin instance to a remote target instance.
+	Export(params *ExportParams) (*TaskInfo, error)
+
+	// ExportWithContext transfers data from your origin instance to a remote target instance with a context for cancellation.
+	ExportWithContext(ctx context.Context, params *ExportParams) (*TaskInfo, error)
+
 	// Close closes the connection to the Meilisearch server.
 	Close()
 }
diff --git a/types.go b/types.go
index d981894..b9beab5 100644
--- a/types.go
+++ b/types.go
@@ -669,3 +669,15 @@ type BatchesQuery struct {
 	AfterStartedAt   time.Time
 	AfterFinishedAt  time.Time
 }
+
+type ExportParams struct {
+	URL         string                        `json:"url,omitempty"`
+	APIKey      string                        `json:"apiKey,omitempty"`
+	PayloadSize string                        `json:"payloadSize,omitempty"`
+	Indexes     map[string]IndexExportOptions `json:"indexes,omitempty"`
+}
+
+type IndexExportOptions struct {
+	Filter           string `json:"filter,omitempty"`
+	OverrideSettings bool   `json:"overrideSettings,omitempty"`
+}



Test patch:
diff --git a/integration/main_test.go b/integration/main_test.go
index c55b942..6f39086 100644
--- a/integration/main_test.go
+++ b/integration/main_test.go
@@ -85,13 +85,17 @@ func setup(t *testing.T, host string, options ...meilisearch.Option) meilisearch
 	opts = append(opts, options...)
 
 	if host == "" {
-		host = getenv("MEILISEARCH_URL", "http://localhost:7700")
+		host = getDefaultHost()
 	}
 
 	sv := meilisearch.New(host, opts...)
 	return sv
 }
 
+func getDefaultHost() string {
+	return getenv("MEILISEARCH_URL", "http://localhost:7700")
+}
+
 func cleanup(services ...meilisearch.ServiceManager) func() {
 	return func() {
 		for _, s := range services {
diff --git a/integration/meilisearch_test.go b/integration/meilisearch_test.go
index c833122..4801122 100644
--- a/integration/meilisearch_test.go
+++ b/integration/meilisearch_test.go
@@ -4,13 +4,14 @@ import (
 	"context"
 	"crypto/tls"
 	"errors"
-	"github.com/meilisearch/meilisearch-go"
 	"math"
 	"strings"
 	"sync"
 	"testing"
 	"time"
 
+	"github.com/meilisearch/meilisearch-go"
+
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -2662,5 +2663,68 @@ func TestGetBatches(t *testing.T) {
 			}
 		})
 	}
+}
 
+func TestExport(t *testing.T) {
+	c := setup(t, "")
+	t.Cleanup(cleanup(c))
+
+	movieIndexUID := "movies"
+	comicsIndexUID := "comics"
+	setupMovieIndex(t, c, movieIndexUID)
+	setupComicIndex(t, c, comicsIndexUID)
+
+	tests := []struct {
+		name   string
+		params *meilisearch.ExportParams
+	}{
+		{
+			name: "ExportWithoutIndexes",
+			params: &meilisearch.ExportParams{
+				URL:         getDefaultHost(),
+				PayloadSize: "1MB",
+				Indexes:     nil,
+			},
+		},
+		{
+			name: "ExportWithOneIndex",
+			params: &meilisearch.ExportParams{
+				URL:         getDefaultHost(),
+				PayloadSize: "10MB",
+				Indexes: map[string]meilisearch.IndexExportOptions{
+					movieIndexUID: {
+						Filter:           "id > 50",
+						OverrideSettings: true,
+					},
+				},
+			},
+		},
+		{
+			name: "ExportWithMultipleIndexes",
+			params: &meilisearch.ExportParams{
+				URL:         getDefaultHost(),
+				PayloadSize: "10MB",
+				Indexes: map[string]meilisearch.IndexExportOptions{
+					movieIndexUID: {
+						Filter:           "id > 86",
+						OverrideSettings: true,
+					},
+					comicsIndexUID: {
+						Filter:           "genres = 'Mystery'",
+						OverrideSettings: false,
+					},
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result, err := c.Export(tt.params)
+			require.NoError(t, err)
+			require.NotZero(t, result.TaskUID)
+			require.Equal(t, meilisearch.TaskStatusEnqueued, result.Status)
+			require.Equal(t, meilisearch.TaskTypeExport, result.Type)
+			require.NotZero(t, result.EnqueuedAt)
+		})
+	}
 }