Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions algoliasearch/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,81 @@ def search_for_facet_values(self, facet_name, facet_query, query=None):
def search_facet(self, facet_name, facet_query, query=None):
return self.search_for_facet_values(facet_name, facet_query, query)

def save_rule(self, rule, forward_to_replicas=False):
"""
Save a new rule in the index.
@param rule the body of the rule to upload as a python dictionary.
the dictionary must contain an objectID key.
@param forward_to_replicas should the rule also be applied to the replicas
of this index? Default is False.
"""
if 'objectID' not in rule:
raise AlgoliaException('missing objectID in rule body')
params = {'forwardToReplicas': forward_to_replicas}
return self._req(False, '/rules/%s' % str(rule['objectID']), 'PUT', params, rule)

def batch_rules(self, rules, forward_to_replicas=False, clear_existing_rules=False):
"""
Save a batch of new rules
@param rules batch of rules to be added to the index. Each rule object must contain
its own objectID.
@param forward_to_replicas should the rules also be applied to the replicas
of this index? Default is False.
@param clear_existing_rules should all the existing rules in the index be cleared
before saving this batch? Default is False.
"""
params = {'forwardToReplicas': forward_to_replicas, 'clearExistingRules': clear_existing_rules}
return self._req(False, '/rules/batch', 'POST', params, data=rules)

def read_rule(self, objectID):
"""
Retrieve a rule from the index with the specified objectID.
@param objectID The objectID of the rule to retrieve
"""
return self._req(False, '/rules/%s' % str(objectID), 'GET')

def delete_rule(self, objectID, forward_to_replicas=False):
"""
Delete the rule with identified by the given objectID.
@param objectID the objectID of the rule to delete
@param forward_to_replicas should the rule also be
deleted from the replicas of the index?
Default is False.
"""
params = {'forwardToReplicas': forward_to_replicas}
return self._req(False, '/rules/%s' % str(objectID), 'DELETE', params)

def clear_rules(self, forward_to_replicas=False):
"""
Clear all the rules of an index.
@param forward_to_replicas Should the rules in the replicas also be cleared?
Default is False.
"""
params = {'forwardToReplicas': forward_to_replicas}
return self._req(False, '/rules/clear', 'POST', params)

def search_rules(self, query=None, anchoring=None, context=None, page=None, hitsPerPage=None):
"""
Search for rules inside the index.
@param query Full text search query
@param anchoring Research the search to rules with a specific anchoring type
@param context Restrict the search to rules with a specific context
@param page Requested page (0 based). Default 0.
@param hitsPerPage Maximum number of hits per page. Default 20.
"""
params = {
'query': query if query else '',
'anchoring': anchoring if anchoring else '',
'context': context if context else '',
}

if page is not None:
params['page'] = page

if hitsPerPage is not None:
params['hitsPerPage'] = hitsPerPage

return self._req(False, '/rules/search', 'POST', params)

def _req(self, is_search, path, meth, params=None, data=None):
"""Perform an HTTPS request with retry logic."""
Expand Down
13 changes: 13 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ def generate_id(self):
self._generated_id.append(new_id)
return str(new_id)

def get_rule_stub(objectID='my-rule'):
return {
'objectID': objectID,
'condition': {
'pattern': 'some text',
'anchoring': 'is'
},
'consequence': {
'params': {
'query': 'other text'
}
}
}

def get_api_client():
if 'APPENGINE_RUNTIME' in os.environ:
Expand Down
69 changes: 66 additions & 3 deletions tests/test_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
from algoliasearch.client import MAX_API_KEY_LENGTH
from algoliasearch.helpers import AlgoliaException

from tests.helpers import safe_index_name
from tests.helpers import get_api_client
from tests.helpers import FakeData
from tests.helpers import safe_index_name, get_api_client, FakeData, get_rule_stub


class IndexTest(unittest.TestCase):
Expand Down Expand Up @@ -191,6 +189,71 @@ def test_facet_search(self):
self.assertEqual(facetHits[0]['value'], 'Peanuts')
self.assertEqual(facetHits[0]['count'], 1)

def test_save_and_get_rule(self):
rule = get_rule_stub()
res = self.index.save_rule(rule)
self.index.wait_task(res['taskID'])
self.assertEqual(rule, self.index.read_rule('my-rule'))

@unittest.expectedFailure
def test_delete_rule(self):
rule = get_rule_stub()
res = self.index.save_rule(rule)
self.index.wait_task(res['taskID'])

res = self.index.delete_rule('my-rule')
self.index.wait_task(res['taskID'])

self.index.read_rule('my-rule')

def test_search_rules(self):
rule = get_rule_stub()
rule2 = get_rule_stub('my-second-rule')

self.index.save_rule(rule);
res = self.index.save_rule(rule2);
self.index.wait_task(res['taskID'])

rules = self.index.search_rules()
self.assertEqual(2, rules['nbHits'])

def test_batch_and_clear_rules(self):
rule = get_rule_stub()
rule2 = get_rule_stub('my-second-rule')

res = self.index.batch_rules([rule, rule2])
self.index.wait_task(res['taskID'])

self.assertEqual(self.index.read_rule('my-rule'), rule)
self.assertEqual(self.index.read_rule('my-second-rule'), rule2)

res = self.index.clear_rules()
self.index.wait_task(res['taskID'])

rules = self.index.search_rules()
self.assertEqual(rules['nbHits'], 0)


def test_batch_and_clear_existing(self):
rule = get_rule_stub()
rule2 = get_rule_stub('my-second-rule')
rule3 = get_rule_stub('my-third-rule')
rule4 = get_rule_stub('my-fourth-rule')

res = self.index.batch_rules([rule, rule2, rule3, rule4])
self.index.wait_task(res['taskID'])

res = self.index.batch_rules([rule3, rule4], False, True)
self.index.wait_task(res['taskID'])

rules = self.index.search_rules()
self.assertEqual(rules['nbHits'], 2)
del rules['hits'][0]['_highlightResult']
del rules['hits'][1]['_highlightResult']

self.assertEqual(rules['hits'], [rule3, rule4]) # alphabetical ordering of objectID


class IndexWithReadOnlyDataTest(IndexTest):
"""Tests that use one index with initial data (read only)."""

Expand Down