Skip to content

Commit e3c0bfc

Browse files
committed
adding delete_by_filter and update_by_filter
1 parent 5e98a1f commit e3c0bfc

3 files changed

Lines changed: 97 additions & 1 deletion

File tree

integrations/supabase/src/haystack_integrations/document_stores/supabase/groonga_document_store.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,48 @@ def write_documents(
234234

235235
return written
236236

237+
def delete_by_filter(self, filters: dict[str, Any]) -> int:
238+
"""
239+
Deletes documents matching the given filters.
240+
241+
:param filters: Filters to select documents for deletion.
242+
:returns: Number of documents deleted.
243+
"""
244+
docs = self.filter_documents(filters=filters)
245+
if not docs:
246+
return 0
247+
self.delete_documents([doc.id for doc in docs])
248+
return len(docs)
249+
250+
def update_by_filter(self, filters: dict[str, Any], meta: dict[str, Any]) -> int:
251+
"""
252+
Updates the metadata of documents matching the given filters.
253+
254+
Provided meta fields are merged into the existing document metadata.
255+
256+
:param filters: Filters to select documents to update.
257+
:param meta: Metadata fields to set on matching documents.
258+
:returns: Number of documents updated.
259+
"""
260+
if self._client is None:
261+
msg = "Call warm_up() before using the document store."
262+
raise RuntimeError(msg)
263+
264+
docs = self.filter_documents(filters=filters)
265+
if not docs:
266+
return 0
267+
268+
for doc in docs:
269+
row = {
270+
"id": doc.id,
271+
"content": doc.content or "",
272+
"meta": {**doc.meta, **meta},
273+
"score": None,
274+
}
275+
self._client.table(self.table_name).upsert(row).execute()
276+
277+
return len(docs)
278+
237279
def delete_all_documents(self) -> None:
238280
"""
239281
Deletes all documents from the store.

integrations/supabase/tests/test_groonga_document_store.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,51 @@ def test_write_documents_fail_on_duplicate(self, groonga_store, mock_supabase_cl
140140
with pytest.raises(DuplicateDocumentError):
141141
groonga_store.write_documents([Document(content="duplicate doc")], policy=DuplicatePolicy.FAIL)
142142

143+
def test_delete_by_filter(self, groonga_store, mock_supabase_client):
144+
mock_table = mock_supabase_client.table.return_value
145+
mock_table.select.return_value.execute.return_value = MagicMock(
146+
data=[{"id": "1", "content": "doc one", "meta": {"lang": "en"}, "score": None}]
147+
)
148+
mock_table.delete.return_value.in_.return_value.execute.return_value = MagicMock(data=[])
149+
150+
deleted = groonga_store.delete_by_filter(
151+
filters={"conditions": [{"field": "meta.lang", "operator": "==", "value": "en"}]}
152+
)
153+
assert deleted == 1
154+
155+
def test_delete_by_filter_no_matches(self, groonga_store, mock_supabase_client):
156+
mock_supabase_client.table.return_value.select.return_value.execute.return_value = MagicMock(data=[])
157+
158+
deleted = groonga_store.delete_by_filter(
159+
filters={"conditions": [{"field": "meta.lang", "operator": "==", "value": "fr"}]}
160+
)
161+
assert deleted == 0
162+
163+
def test_update_by_filter(self, groonga_store, mock_supabase_client):
164+
mock_table = mock_supabase_client.table.return_value
165+
mock_table.select.return_value.execute.return_value = MagicMock(
166+
data=[{"id": "1", "content": "doc one", "meta": {"lang": "en"}, "score": None}]
167+
)
168+
mock_table.upsert.return_value.execute.return_value = MagicMock(data=[{}])
169+
170+
updated = groonga_store.update_by_filter(
171+
filters={"conditions": [{"field": "meta.lang", "operator": "==", "value": "en"}]},
172+
meta={"reviewed": True},
173+
)
174+
assert updated == 1
175+
mock_table.upsert.assert_called_once()
176+
upserted_row = mock_table.upsert.call_args[0][0]
177+
assert upserted_row["meta"] == {"lang": "en", "reviewed": True}
178+
179+
def test_update_by_filter_no_matches(self, groonga_store, mock_supabase_client):
180+
mock_supabase_client.table.return_value.select.return_value.execute.return_value = MagicMock(data=[])
181+
182+
updated = groonga_store.update_by_filter(
183+
filters={"conditions": [{"field": "meta.lang", "operator": "==", "value": "fr"}]},
184+
meta={"reviewed": True},
185+
)
186+
assert updated == 0
187+
143188
def test_delete_all_documents(self, groonga_store, mock_supabase_client):
144189
mock_table = mock_supabase_client.table.return_value
145190
mock_table.delete.return_value.neq.return_value.execute.return_value = MagicMock(data=[])

integrations/supabase/tests/test_groonga_integration.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
from haystack.document_stores.types import DuplicatePolicy
1111
from haystack.testing.document_store import (
1212
DeleteAllTest,
13+
DeleteByFilterTest,
1314
DocumentStoreBaseTests,
15+
FilterableDocsFixtureMixin,
16+
UpdateByFilterTest,
1417
)
1518
from haystack.utils import Secret
1619

@@ -43,7 +46,13 @@ def document_store(request):
4346

4447

4548
@pytest.mark.integration
46-
class TestSupabaseGroongaDocumentStoreIntegration(DocumentStoreBaseTests, DeleteAllTest):
49+
class TestSupabaseGroongaDocumentStoreIntegration(
50+
DocumentStoreBaseTests,
51+
DeleteAllTest,
52+
DeleteByFilterTest,
53+
FilterableDocsFixtureMixin,
54+
UpdateByFilterTest,
55+
):
4756
pass
4857

4958

0 commit comments

Comments
 (0)