Skip to content

Commit 09a8077

Browse files
committed
feat: Add export api
1 parent cde48b9 commit 09a8077

File tree

7 files changed

+139
-7
lines changed

7 files changed

+139
-7
lines changed

.code-samples.meilisearch.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,16 @@ faceted_search_1: |-
514514
})
515515
post_dump_1: |-
516516
client.create_dump()
517+
export_post_1: |-
518+
client.export(
519+
url='https://remote-meilisearch-instance.com',
520+
api_key='masterKey',
521+
pay_load_size='50MiB',
522+
indexes={
523+
'movies*': {},
524+
'books*': {},
525+
},
526+
)
517527
phrase_search_1: |-
518528
client.index('movies').search('"african american" horror')
519529
sorting_guide_update_sortable_attributes_1: |-

docker-compose.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ services:
66
working_dir: /home/package
77
environment:
88
- MEILISEARCH_URL=http://meilisearch:7700
9+
- MEILISEARCH_URL_2=http://meilisearch2:7700
910
depends_on:
1011
- meilisearch
12+
- meilisearch2
1113
links:
1214
- meilisearch
15+
- meilisearch2
1316
volumes:
1417
- ./:/home/package
1518

@@ -20,3 +23,12 @@ services:
2023
environment:
2124
- MEILI_MASTER_KEY=masterKey
2225
- MEILI_NO_ANALYTICS=true
26+
27+
meilisearch2:
28+
image: getmeili/meilisearch:latest
29+
container_name: meili2
30+
ports:
31+
- "7701:7700"
32+
environment:
33+
- MEILI_MASTER_KEY=masterKey
34+
- MEILI_NO_ANALYTICS=true

meilisearch/client.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,57 @@ def create_dump(self) -> TaskInfo:
627627

628628
return TaskInfo(**task)
629629

630+
def export(
631+
self,
632+
url: str,
633+
api_key: Optional[str] = None,
634+
pay_load_size: Optional[str] = None,
635+
indexes: Optional[Mapping[str, Any]] = None,
636+
) -> TaskInfo:
637+
"""Trigger the creation of a Meilisearch export.
638+
639+
Parameters
640+
----------
641+
url:
642+
A string pointing to a remote Meilisearch instance, including its port if necessary.
643+
644+
api_key:
645+
A security key with index.create, settings.update, and documents.add permissions
646+
to a secured Meilisearch instance.
647+
648+
pay_load_size:
649+
The maximum size of each single data payload in a human-readable format such as "100MiB".
650+
Larger payloads are generally more efficient, but require significantly more powerful machines.
651+
652+
indexes:
653+
A set of objects whose keys correspond to patterns matching the indexes you want to export.
654+
By default, Meilisearch exports all documents across all indexes.
655+
656+
Returns
657+
-------
658+
task_info:
659+
TaskInfo instance containing information about a task to track the progress of an asynchronous process.
660+
https://www.meilisearch.com/docs/reference/api/export#create-an-export
661+
662+
Raises
663+
------
664+
MeilisearchApiError
665+
An error containing details about why Meilisearch can't process your request.
666+
Meilisearch error codes are described
667+
here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors
668+
"""
669+
payload: Dict[str, Any] = {"url": url}
670+
if api_key is not None:
671+
payload["apiKey"] = api_key
672+
if pay_load_size is not None:
673+
payload["payloadSize"] = pay_load_size
674+
if indexes is not None:
675+
payload["indexes"] = indexes
676+
677+
task = self.http.post(self.config.paths.exports, body=payload)
678+
679+
return TaskInfo(**task)
680+
630681
def create_snapshot(self) -> TaskInfo:
631682
"""Trigger the creation of a Meilisearch snapshot.
632683

meilisearch/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class Paths:
4848
edit = "edit"
4949
network = "network"
5050
webhooks = "webhooks"
51+
exports = "export"
5152

5253
def __init__(
5354
self,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
3+
import pytest
4+
5+
from tests import common
6+
7+
pytestmark = pytest.mark.skipif(
8+
not os.getenv("MEILISEARCH_URL_2"),
9+
reason="Export API tests run only when second server is configured",
10+
)
11+
12+
13+
def test_export_creation(client, client2, index_with_documents):
14+
"""Tests the creation of a Meilisearch export."""
15+
index = index_with_documents()
16+
export_task = client.export(common.BASE_URL_2, api_key=common.MASTER_KEY)
17+
task_result = client.wait_for_task(export_task.task_uid)
18+
assert task_result.status == "succeeded"
19+
20+
index2 = client2.get_index(index.uid)
21+
assert index2.uid == index.uid
22+
assert index2.primary_key == index.get_primary_key()
23+
assert index2.get_documents().total == index.get_documents().total
24+
25+
26+
def test_export_creation_with_index_filter(client, client2, index_with_documents):
27+
"""Tests the creation of a Meilisearch export with specific index UIDs."""
28+
index_with_documents()
29+
index = index_with_documents(common.INDEX_UID2)
30+
31+
indexes = {common.INDEX_UID2: {"filter": None}}
32+
export_task = client.export(common.BASE_URL_2, api_key=common.MASTER_KEY, indexes=indexes)
33+
task_result = client.wait_for_task(export_task.task_uid)
34+
assert task_result.status == "succeeded"
35+
36+
response = client2.get_indexes()
37+
assert response["total"] == 1
38+
index2 = client2.get_index(common.INDEX_UID2)
39+
40+
assert index2.uid == index.uid
41+
assert index2.primary_key == index.get_primary_key()
42+
assert index.get_documents().total == index2.get_documents().total

tests/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
MASTER_KEY = "masterKey"
44
BASE_URL = os.getenv("MEILISEARCH_URL", "http://127.0.0.1:7700")
5+
BASE_URL_2 = os.getenv("MEILISEARCH_URL_2", "http://127.0.0.1:7701")
56

67
INDEX_UID = "indexUID"
78
INDEX_UID2 = "indexUID2"

tests/conftest.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# pylint: disable=redefined-outer-name
2+
import os
23
import json
34
from typing import Optional
45

@@ -16,19 +17,31 @@ def client():
1617
return meilisearch.Client(common.BASE_URL, common.MASTER_KEY)
1718

1819

20+
@fixture(scope="session")
21+
def client2():
22+
return meilisearch.Client(common.BASE_URL_2, common.MASTER_KEY)
23+
24+
25+
def _clear_indexes(meilisearch_client):
26+
"""Deletes all the indexes in the Meilisearch instance."""
27+
28+
indexes = meilisearch_client.get_indexes()
29+
for index in indexes["results"]:
30+
task = meilisearch_client.index(index.uid).delete()
31+
meilisearch_client.wait_for_task(task.task_uid)
32+
33+
1934
@fixture(autouse=True)
20-
def clear_indexes(client):
35+
def clear_indexes(client, client2):
2136
"""
2237
Auto-clears the indexes after each test function run.
2338
Makes all the test functions independent.
2439
"""
2540
# Yields back to the test function.
2641
yield
27-
# Deletes all the indexes in the Meilisearch instance.
28-
indexes = client.get_indexes()
29-
for index in indexes["results"]:
30-
task = client.index(index.uid).delete()
31-
client.wait_for_task(task.task_uid)
42+
_clear_indexes(client)
43+
if os.getenv("MEILISEARCH_URL_2"):
44+
_clear_indexes(client2)
3245

3346

3447
@fixture(autouse=True)
@@ -47,12 +60,14 @@ def clear_webhooks(client):
4760

4861

4962
@fixture(autouse=True)
50-
def clear_all_tasks(client):
63+
def clear_all_tasks(client, client2):
5164
"""
5265
Auto-clears the tasks after each test function run.
5366
Makes all the test functions independent.
5467
"""
5568
client.delete_tasks({"statuses": ["succeeded", "failed", "canceled"]})
69+
if os.getenv("MEILISEARCH_URL_2"):
70+
client2.delete_tasks({"statuses": ["succeeded", "failed", "canceled"]})
5671

5772

5873
@fixture(scope="function")

0 commit comments

Comments
 (0)