Skip to content

Commit 73b1293

Browse files
committed
RDBC-780 RavenDB_8355Test::canUseCustomSorter
1 parent 5084a14 commit 73b1293

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from typing import List, TYPE_CHECKING
2+
3+
import requests
4+
5+
from ravendb import SorterDefinition, RaftCommand, ServerNode
6+
from ravendb.documents.operations.definitions import VoidMaintenanceOperation
7+
from ravendb.http.raven_command import VoidRavenCommand
8+
from ravendb.util.util import RaftIdGenerator
9+
10+
if TYPE_CHECKING:
11+
from ravendb.documents.conventions import DocumentConventions
12+
13+
14+
class PutSortersOperation(VoidMaintenanceOperation):
15+
def __init__(self, *sorters_to_add: SorterDefinition):
16+
if not sorters_to_add:
17+
raise ValueError("Sorters must not be empty or None")
18+
19+
self._sorters_to_add = sorters_to_add
20+
21+
def get_command(self, conventions: "DocumentConventions") -> "PutSortersOperation.PutSortersCommand":
22+
return self.PutSortersCommand(conventions, list(self._sorters_to_add))
23+
24+
class PutSortersCommand(VoidRavenCommand, RaftCommand):
25+
def __init__(self, conventions: "DocumentConventions", sorters_to_add: List[SorterDefinition]):
26+
if conventions is None:
27+
raise ValueError("Conventions cannot be None")
28+
29+
if sorters_to_add is None:
30+
raise ValueError("Sorters cannot be None")
31+
32+
if any([sorter is None for sorter in sorters_to_add]):
33+
raise ValueError("Sorter cannot be None")
34+
35+
super().__init__()
36+
37+
self._sorters_to_add = sorters_to_add
38+
39+
def create_request(self, node: ServerNode) -> requests.Request:
40+
url = f"{node.url}/databases/{node.database}/admin/sorters"
41+
42+
request = requests.Request("PUT", url)
43+
request.data = {"Sorters": [sorter.to_json() for sorter in self._sorters_to_add]}
44+
45+
return request
46+
47+
def is_read_request(self) -> bool:
48+
return False
49+
50+
def get_raft_unique_request_id(self) -> str:
51+
return RaftIdGenerator.new_id()

ravendb/documents/session/tokens/query_tokens/definitions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,10 @@ def score_descending(cls) -> OrderByToken:
274274
def __init__(self, field_name: str, descending: bool, ordering_or_sorter_name: Union[OrderingType, str]):
275275
self.__field_name = field_name
276276
self.__descending = descending
277+
278+
# duck typing the arg
277279
is_ordering = isinstance(ordering_or_sorter_name, OrderingType)
280+
278281
self.__ordering = ordering_or_sorter_name if is_ordering else None
279282
self.__sorter_name = None if is_ordering else ordering_or_sorter_name
280283

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from typing import Type
2+
3+
from ravendb import SorterDefinition, DocumentStore, RawDocumentQuery, DocumentQuery
4+
from ravendb.documents.operations.sorters import PutSortersOperation
5+
from ravendb.exceptions.raven_exceptions import RavenException
6+
from ravendb.infrastructure.orders import Company
7+
from ravendb.tests.test_base import TestBase
8+
9+
sorter_code = (
10+
"using System;\n"
11+
"using System.Collections.Generic;\n"
12+
"using Lucene.Net.Index;\n"
13+
"using Lucene.Net.Search;\n"
14+
"using Lucene.Net.Store;\n"
15+
"\n"
16+
"namespace SlowTests.Data.RavenDB_8355\n"
17+
"{\n"
18+
" public class MySorter : FieldComparator\n"
19+
" {\n"
20+
" private readonly string _args;\n"
21+
"\n"
22+
" public MySorter(string fieldName, int numHits, int sortPos, bool reversed, List<string> diagnostics)\n"
23+
" {\n"
24+
' _args = $"{fieldName}:{numHits}:{sortPos}:{reversed}";\n'
25+
" }\n"
26+
"\n"
27+
" public override int Compare(int slot1, int slot2)\n"
28+
" {\n"
29+
' throw new InvalidOperationException($"Catch me: {_args}");\n'
30+
" }\n"
31+
"\n"
32+
" public override void SetBottom(int slot)\n"
33+
" {\n"
34+
' throw new InvalidOperationException($"Catch me: {_args}");\n'
35+
" }\n"
36+
"\n"
37+
" public override int CompareBottom(int doc, IState state)\n"
38+
" {\n"
39+
' throw new InvalidOperationException($"Catch me: {_args}");\n'
40+
" }\n"
41+
"\n"
42+
" public override void Copy(int slot, int doc, IState state)\n"
43+
" {\n"
44+
' throw new InvalidOperationException($"Catch me: {_args}");\n'
45+
" }\n"
46+
"\n"
47+
" public override void SetNextReader(IndexReader reader, int docBase, IState state)\n"
48+
" {\n"
49+
' throw new InvalidOperationException($"Catch me: {_args}");\n'
50+
" }\n"
51+
"\n"
52+
' public override IComparable this[int slot] => throw new InvalidOperationException($"Catch me: {_args}");\n'
53+
" }\n"
54+
"}\n"
55+
)
56+
57+
58+
class TestRavenDB8355(TestBase):
59+
def setUp(self):
60+
super().setUp()
61+
62+
def test_can_use_custom_sorter(self):
63+
sorter_definition = SorterDefinition("MySorter", sorter_code)
64+
operation = PutSortersOperation(sorter_definition)
65+
66+
self.store.maintenance.send(operation)
67+
68+
with self.store.open_session() as session:
69+
company1 = Company(name="C1")
70+
session.store(company1)
71+
72+
company2 = Company(name="C2")
73+
session.store(company2)
74+
75+
session.save_changes()
76+
77+
self._can_use_sorter_internal(RuntimeError, self.store, "Catch me: name:2:0:False", "Catch me: name:2:0:True")
78+
79+
def _can_use_sorter_internal(self, expected_class: Type[Exception], store: DocumentStore, asc: str, desc: str) -> None:
80+
with store.open_session() as session:
81+
self.assertRaisesWithMessageContaining(
82+
RawDocumentQuery.__iter__,
83+
expected_class,
84+
asc,
85+
session.advanced.raw_query("from Companies order by custom(name, 'MySorter')"),
86+
)
87+
self.assertRaisesWithMessageContaining(
88+
DocumentQuery.__iter__,
89+
expected_class,
90+
asc,
91+
session.query(object_type=Company).order_by(field="name", sorter_name_or_ordering_type="MySorter"),
92+
)
93+
94+
self.assertRaisesWithMessageContaining(
95+
RawDocumentQuery.__iter__,
96+
expected_class,
97+
desc,
98+
session.advanced.raw_query("from Companies order by custom(name, 'MySorter') desc"),
99+
)
100+
self.assertRaisesWithMessageContaining(
101+
DocumentQuery.__iter__,
102+
expected_class,
103+
desc,
104+
session.query(object_type=Company).order_by_descending(
105+
field="name", sorter_name_or_ordering_type="MySorter"
106+
),
107+
)

0 commit comments

Comments
 (0)