From 26d64ed3570698d2f882e5eab4a25c13791d0495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Mon, 16 Apr 2018 15:06:27 +0200 Subject: [PATCH] Add contains and contains_all filters. Fixes #343 Co-authored-by: Julien Lebunetel --- kinto/core/storage/memory.py | 8 ++++++++ kinto/core/storage/testing.py | 32 ++++++++++++++++++++++++++++++++ kinto/core/utils.py | 2 ++ 3 files changed, 42 insertions(+) diff --git a/kinto/core/storage/memory.py b/kinto/core/storage/memory.py index bf8fe8729..1478f8884 100644 --- a/kinto/core/storage/memory.py +++ b/kinto/core/storage/memory.py @@ -326,6 +326,12 @@ def extract_record_set(records, filters, sorting, def apply_filters(records, filters): """Filter the specified records, using basic iteration. """ + + def contains_all_filtering(record_value, search_term): + search_set = set(search_term[1]) + record_value_set = set(record_value[1]) + return record_value_set.intersection(search_set) == search_set + operators = { COMPARISON.LT: operator.lt, COMPARISON.MAX: operator.le, @@ -336,6 +342,8 @@ def apply_filters(records, filters): COMPARISON.IN: operator.contains, COMPARISON.EXCLUDE: lambda x, y: not operator.contains(x, y), COMPARISON.LIKE: lambda x, y: re.search(y, x, re.IGNORECASE), + COMPARISON.CONTAINS_ALL: contains_all_filtering, + COMPARISON.CONTAINS: lambda record_value, search_term: set(record_value[1]).intersection(set(search_term[1])) } for record in records: matches = True diff --git a/kinto/core/storage/testing.py b/kinto/core/storage/testing.py index 4d12c81c4..34ff81354 100644 --- a/kinto/core/storage/testing.py +++ b/kinto/core/storage/testing.py @@ -390,6 +390,38 @@ def test_get_all_can_filter_with_list_of_values(self): **self.storage_kw) self.assertEqual(len(records), 2) + def test_get_all_can_filter_on_array_that_contains_all_values(self): + self.create_record({'colors': ["red", "green", "blue"]}) + self.create_record({'colors': ["gray", "blue"]}) + self.create_record({'colors': ["red", "gray", "blue"]}) + self.create_record({'colors': ["purple", "green", "blue"]}) + + filters = [Filter('colors', ['red'], utils.COMPARISON.CONTAINS_ALL)] + records, _ = self.storage.get_all(filters=filters, + **self.storage_kw) + self.assertEqual(len(records), 2) + + filters = [Filter('colors', ['red', 'gray'], utils.COMPARISON.CONTAINS_ALL)] + records, _ = self.storage.get_all(filters=filters, + **self.storage_kw) + self.assertEqual(len(records), 1) + + def test_get_all_can_filter_on_array_that_contains_at_least_one_value(self): + self.create_record({'colors': ["red", "green", "blue"]}) + self.create_record({'colors': ["gray", "blue"]}) + self.create_record({'colors': ["red", "gray", "blue"]}) + self.create_record({'colors': ["purple", "green", "blue"]}) + + filters = [Filter('colors', ['red'], utils.COMPARISON.CONTAINS)] + records, _ = self.storage.get_all(filters=filters, + **self.storage_kw) + self.assertEqual(len(records), 2) + + filters = [Filter('colors', ['red', 'gray'], utils.COMPARISON.CONTAINS)] + records, _ = self.storage.get_all(filters=filters, + **self.storage_kw) + self.assertEqual(len(records), 3) + def test_get_all_can_filter_with_numeric_values(self): self.create_record({'missing': 'code'}) for l in [1, 10, 6, 46]: diff --git a/kinto/core/utils.py b/kinto/core/utils.py index a7a39233c..5bc521562 100644 --- a/kinto/core/utils.py +++ b/kinto/core/utils.py @@ -226,6 +226,8 @@ class COMPARISON(Enum): EXCLUDE = 'exclude' LIKE = 'like' HAS = 'has' + CONTAINS_ALL = 'contains_all' + CONTAINS = 'contains' def reapply_cors(request, response):