Skip to content

Commit 5df4f85

Browse files
committed
RDBC-1040 Add JavaScriptArray.remove_all(predicate) method
Emits 'this.{path} = this.{path}.filter(function(item){ return !(predicate); });' matching the C# RemoveAll behavior (filter with negated predicate, assignment back to path).
1 parent 556d1e0 commit 5df4f85

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

ravendb/documents/session/misc.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ def remove_at(self, index: int) -> JavaScriptArray:
253253

254254
return self
255255

256+
def remove_all(self, predicate_js: str) -> "JavaScriptArray":
257+
path = self.__path_to_array
258+
self.__script_lines.append(f"this.{path} = this.{path}.filter(function(item){{ return !({predicate_js}); }});")
259+
return self
260+
256261

257262
class JavaScriptMap(Generic[_T_Key, _T_Value]):
258263
def __init__(self, suffix: int, path_to_map: str):
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
RDBC-1040: JavaScriptArray.remove_all(predicate_js) emits correct JS filter.
3+
4+
C# reference: JavaScriptArray<T>.RemoveAll(Func<T,bool>)
5+
"""
6+
7+
import unittest
8+
9+
from ravendb.documents.session.misc import JavaScriptArray
10+
from ravendb.tests.test_base import TestBase
11+
12+
13+
class TestJavaScriptArrayRemoveAllUnit(unittest.TestCase):
14+
"""Unit tests — no server required."""
15+
16+
def test_remove_all_generates_correct_js(self):
17+
arr = JavaScriptArray(0, "items")
18+
arr.remove_all("item > 5")
19+
script = arr.script
20+
self.assertIn("filter", script)
21+
self.assertIn("item > 5", script)
22+
23+
def test_remove_all_uses_filter_assignment(self):
24+
arr = JavaScriptArray(0, "values")
25+
arr.remove_all("item === 'bad'")
26+
script = arr.script
27+
self.assertIn("this.values =", script)
28+
self.assertIn(".filter(", script)
29+
30+
def test_remove_all_negates_predicate(self):
31+
arr = JavaScriptArray(0, "tags")
32+
arr.remove_all("item === 'x'")
33+
script = arr.script
34+
# The predicate should be negated with !()
35+
self.assertIn("!(", script)
36+
37+
def test_remove_all_chaining_with_add(self):
38+
# C# uses expression trees so the compiler catches a broken add() at compile time.
39+
# In Python there is no equivalent static check, so both halves of the chain must
40+
# be asserted explicitly here.
41+
arr = JavaScriptArray(1, "tags")
42+
arr.add("new_tag").remove_all("item === 'old_tag'")
43+
script = arr.script
44+
self.assertIn("push", script)
45+
self.assertIn("filter", script)
46+
47+
def test_remove_all_returns_self_for_chaining(self):
48+
arr = JavaScriptArray(0, "items")
49+
result = arr.remove_all("item > 0")
50+
self.assertIs(arr, result)
51+
52+
53+
class TestJavaScriptArrayRemoveAllIntegration(TestBase):
54+
"""Integration tests — require a live server."""
55+
56+
def setUp(self):
57+
super().setUp()
58+
self.store = self.get_document_store()
59+
60+
def tearDown(self):
61+
super().tearDown()
62+
self.store.close()
63+
64+
def test_remove_all_via_patch_removes_matching_items(self):
65+
from ravendb.documents.operations.patch import PatchOperation, PatchRequest
66+
67+
class DocWithList:
68+
def __init__(self, items=None):
69+
self.items = items or []
70+
71+
with self.store.open_session() as session:
72+
doc = DocWithList(items=[1, 2, 3, 4, 5, 6])
73+
session.store(doc, "docs/1")
74+
session.save_changes()
75+
76+
patch_request = PatchRequest()
77+
arr = JavaScriptArray(0, "items")
78+
arr.remove_all("item > 3")
79+
patch_request.script = arr.script
80+
patch_request.values = {}
81+
82+
self.store.operations.send(PatchOperation("docs/1", None, patch_request))
83+
84+
with self.store.open_session() as session:
85+
loaded = session.load("docs/1", DocWithList)
86+
self.assertEqual([1, 2, 3], sorted(loaded.items))
87+
88+
89+
if __name__ == "__main__":
90+
unittest.main()

0 commit comments

Comments
 (0)