Skip to content
Open
21 changes: 21 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -610,3 +610,24 @@ update_embedders_1: |-
})
reset_embedders_1: |-
client.index('INDEX_NAME').reset_embedders()
list_dynamic_search_rules_1: |-
client.get_dynamic_search_rules()
get_dynamic_search_rule_1: |-
client.get_dynamic_search_rule('RULE_UID')
patch_dynamic_search_rule_1: |-
client.create_or_update_dynamic_search_rule('RULE_UID', {
'description': 'Rule description',
'priority': 10,
'active': True,
'conditions': [
{'scope': 'query', 'isEmpty': True}
],
'actions': [
{
'selector': {'indexUid': 'movies', 'id': '123'},
'action': {'type': 'pin', 'position': 1}
}
],
})
delete_dynamic_search_rule_1: |-
client.delete_dynamic_search_rule('RULE_UID')
100 changes: 100 additions & 0 deletions meilisearch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from meilisearch.models.key import Key, KeysResults
from meilisearch.models.task import Batch, BatchResults, Task, TaskInfo, TaskResults
from meilisearch.models.webhook import Webhook, WebhooksResults
from meilisearch.models.dynamic_search_rule import DynamicSearchRule, DynamicSearchRuleResults
from meilisearch.task import TaskHandler


Expand Down Expand Up @@ -600,6 +601,105 @@ def delete_webhook(self, webhook_uuid: str) -> int:
"""
response = self.http.delete(f"{self.config.paths.webhooks}/{webhook_uuid}")
return response.status_code

# DYNAMIC SEARCH RULES ROUTES

def get_dynamic_search_rules(self) -> DynamicSearchRuleResults:
"""Get all dynamic search rules.

Returns
-------
rules:
DynamicSearchRuleResults instance containing list of rules and pagination info.
https://www.meilisearch.com/docs/reference/api/dynamic-search-rules/list-dynamic-search-rules

Raises
------
MeilisearchApiError
An error containing details about why Meilisearch can't process your request.
Meilisearch error codes are described here:
https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors
"""
rules = self.http.post(self.config.paths.dynamic_search_rules, {})
return DynamicSearchRuleResults(**rules)

def get_dynamic_search_rule(self, uid: str) -> DynamicSearchRule:
"""Get information about a specific dynamic search rule.

Parameters
----------
uid:
The uid of the dynamic search rule to retrieve.

Returns
-------
rule:
The dynamic search rule information.
https://www.meilisearch.com/docs/reference/api/dynamic-search-rules/get-a-dynamic-search-rule

Raises
------
MeilisearchApiError
An error containing details about why Meilisearch can't process your request.
Meilisearch error codes are described here:
https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors
"""
rule = self.http.get(f"{self.config.paths.dynamic_search_rules}/{uid}")
return DynamicSearchRule(**rule)

def create_or_update_dynamic_search_rule(
self, uid: str, options: Mapping[str, Any]
) -> DynamicSearchRule:
"""Create or update a dynamic search rule.

Parameters
----------
uid:
The uid of the dynamic search rule to create or update.
options:
The dynamic search rule fields to create or update.

Returns
-------
rule:
The created or updated dynamic search rule.
https://www.meilisearch.com/docs/reference/api/dynamic-search-rules/create-or-update-a-dynamic-search-rule

Raises
------
MeilisearchApiError
An error containing details about why Meilisearch can't process your request.
Meilisearch error codes are described here:
https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors
"""
rule = self.http.patch(f"{self.config.paths.dynamic_search_rules}/{uid}", options)
return DynamicSearchRule(**rule)


def delete_dynamic_search_rule(self, uid: str) -> int:
"""Delete a dynamic search rule.

Parameters
----------
uid:
The uid of the dynamic search rule to delete.

Returns
-------
status_code:
The Response status code. 204 signifies a successful delete.
https://www.meilisearch.com/docs/reference/api/dynamic-search-rules/delete-a-dynamic-search-rule

Raises
------
MeilisearchApiError
An error containing details about why Meilisearch can't process your request.
Meilisearch error codes are described here:
https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors
"""
response = self.http.delete(f"{self.config.paths.dynamic_search_rules}/{uid}")
return response.status_code


def get_version(self) -> Dict[str, str]:
"""Get version Meilisearch
Expand Down
1 change: 1 addition & 0 deletions meilisearch/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Paths:
network = "network"
experimental_features = "experimental-features"
webhooks = "webhooks"
dynamic_search_rules = "dynamic-search-rules"
export = "export"

def __init__(
Expand Down
27 changes: 27 additions & 0 deletions meilisearch/models/dynamic_search_rule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Any, Dict, List, Optional

from camel_converter.pydantic_base import CamelBase
from pydantic import ConfigDict


class DynamicSearchRule(CamelBase):
"""Model for a Meilisearch dynamic search rule."""

model_config = ConfigDict(arbitrary_types_allowed=True)
Comment thread
w1ndcn marked this conversation as resolved.
Outdated

uid: str
description: Optional[str] = None
priority: Optional[int] = None
active: Optional[bool] = None
conditions: Optional[List[Dict[str, Any]]] = None
actions: Optional[List[Dict[str, Any]]] = None
Comment thread
w1ndcn marked this conversation as resolved.
Outdated


class DynamicSearchRuleResults(CamelBase):
"""Model for dynamic search rules list results."""

model_config = ConfigDict(arbitrary_types_allowed=True)
Comment thread
w1ndcn marked this conversation as resolved.
Outdated
results: List[DynamicSearchRule]
offset: int
limit: int
total: int
120 changes: 120 additions & 0 deletions tests/client/test_client_dynamic_search_rules_meilisearch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""Tests for dynamic search rule management endpoints."""

import pytest

from meilisearch.errors import MeilisearchApiError


def test_get_dynamic_search_rules_empty(client):
"""Test getting dynamic search rules when none exist."""
rules = client.get_dynamic_search_rules()
assert rules.results is not None
assert isinstance(rules.results, list)
assert len(rules.results) == 0

Comment thread
w1ndcn marked this conversation as resolved.

def test_create_or_update_dynamic_search_rule(client):
"""Test creating a dynamic search rule."""
rule_data = {
"description": "Test rule for promotion",
"priority": 10,
"active": True,
"conditions": [
{"scope": "query", "isEmpty": True}
],
"actions": [
{
"selector": {"indexUid": "movies", "id": "123"},
"action": {"type": "pin", "position": 1}
}
],
}

rule = client.create_or_update_dynamic_search_rule("test-rule", rule_data)

assert rule.uid == "test-rule"
assert rule.description == rule_data["description"]
assert rule.priority == 10
assert rule.active is True


def test_get_dynamic_search_rule(client):
"""Test getting a single dynamic search rule."""
# Create a rule first
rule_data = {
"description": "Test rule",
"active": True,
}

created_rule = client.create_or_update_dynamic_search_rule("test-rule", rule_data)

# Get the rule
rule = client.get_dynamic_search_rule(created_rule.uid)

assert rule.uid == created_rule.uid
assert rule.description == rule_data["description"]


def test_get_dynamic_search_rule_not_found(client):
"""Test getting a dynamic search rule that doesn't exist."""
with pytest.raises(MeilisearchApiError):
client.get_dynamic_search_rule("non-existent-uid")


def test_update_dynamic_search_rule(client):
"""Test updating a dynamic search rule."""
# Create a rule first
rule_data = {
"description": "Original description",
"priority": 10,
"active": True,
"conditions": [
{"scope": "query", "isEmpty": True}
],
"actions": [
{
"selector": {"indexUid": "movies", "id": "123"},
"action": {"type": "pin", "position": 1}
}
],
}

created_rule = client.create_or_update_dynamic_search_rule("test-rule", rule_data)

# Update the rule
update_data = {
"description": "Updated description",
"priority": 5,
}

updated_rule = client.create_or_update_dynamic_search_rule(created_rule.uid, update_data)

assert updated_rule.uid == created_rule.uid
assert updated_rule.description == update_data["description"]
assert updated_rule.priority == 5


def test_delete_dynamic_search_rule(client):
"""Test deleting a dynamic search rule."""
# Create a rule first
rule_data = {
"description": "Rule to delete",
"active": True,
}

created_rule = client.create_or_update_dynamic_search_rule("test-rule", rule_data)

# Delete the rule
status_code = client.delete_dynamic_search_rule(created_rule.uid)

assert status_code == 204

# Verify it's deleted
with pytest.raises(MeilisearchApiError):
client.get_dynamic_search_rule(created_rule.uid)


def test_delete_dynamic_search_rule_not_found(client):
"""Test deleting a dynamic search rule that doesn't exist."""
with pytest.raises(MeilisearchApiError):
client.delete_dynamic_search_rule("non-existent-uid")
Loading