Skip to content

Commit 9ddcbd7

Browse files
committed
Merge branch 'v5.0' of https://github.com/ravendb/ravendb-python-client into v5.0
2 parents 4b98424 + 144a016 commit 9ddcbd7

File tree

3 files changed

+183
-5
lines changed

3 files changed

+183
-5
lines changed

pyravendb/commands/raven_commands.py

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,34 +57,55 @@ def is_failed_with_node(self, node):
5757

5858

5959
class GetDocumentCommand(RavenCommand):
60-
def __init__(self, key_or_keys, includes=None, metadata_only=False):
60+
def __init__(self, key_or_keys, includes=None, metadata_only=False, start=None, page_size=None,
61+
counter_includes=None):
6162
"""
6263
@param key_or_keys: the key of the documents you want to retrieve (key can be a list of ids)
6364
:type str or list
6465
@param includes: array of paths in documents in which server should look for a 'referenced' document
6566
:type list
6667
@param metadata_only: specifies if only document metadata should be returned
6768
:type bool
69+
@param start: number of results to skip.
70+
type: int
71+
@param page_size: maximum number of results to retrieve
72+
type: int
73+
@param counter_includes: the names of the counters to be included or True to include all counters
74+
type: list[str] or bool
6875
@return: A list of the id or ids we looked for (if they exists)
6976
:rtype: dict
7077
"""
7178
super(GetDocumentCommand, self).__init__(method="GET", is_read_request=True)
7279
self.key_or_keys = key_or_keys
7380
self.includes = includes
7481
self.metadata_only = metadata_only
82+
self.start = start
83+
self.page_size = page_size
84+
self.counter_includes = counter_includes
7585

76-
def create_request(self, server_node):
7786
if self.key_or_keys is None:
7887
raise ValueError("None Key is not valid")
88+
89+
def create_request(self, server_node):
7990
path = "docs?"
91+
92+
if self.start:
93+
path += f"&start={self.start}"
94+
if self.page_size:
95+
path += f"&pageSize={self.page_size}"
96+
if self.metadata_only:
97+
path += "&metadataOnly=true"
8098
if self.includes:
8199
path += "".join("&include=" + Utils.quote_key(item) for item in self.includes)
100+
if self.counter_includes:
101+
if self.counter_includes is True:
102+
path += f"&counter={Utils.quote_key('@all_counters')}"
103+
else:
104+
path += "".join("&counter=" + Utils.quote_key(item) for item in self.counter_includes)
105+
82106
# make get method handle a multi document requests in a single request
83107
if isinstance(self.key_or_keys, list):
84108
key_or_keys = collections.OrderedDict.fromkeys(self.key_or_keys)
85-
if self.metadata_only:
86-
path += "&metadataOnly=true"
87-
88109
# If it is too big, we drop to POST (note that means that we can't use the HTTP cache any longer)
89110
if (sum(len(x) for x in key_or_keys)) > 1024:
90111
self.method = "POST"
@@ -111,6 +132,82 @@ def set_response(self, response):
111132
return response
112133

113134

135+
class GetDocumentsByPrefixCommand(RavenCommand):
136+
def __init__(self, start_with, start_after=None, matches=None, exclude=None, start=None, page_size=None,
137+
metadata_only=None):
138+
139+
"""
140+
@param start_with: Retrieve all documents whose IDs begin with this string.
141+
If the value of this parameter is left empty, all documents in the database are retrieved.
142+
:type str
143+
144+
@param start_after: Retrieve only the results after the first document ID that begins with this prefix.
145+
:type str
146+
147+
@param matches: Retrieve documents whose IDs are exactly <startsWith>+<matches>.
148+
Accepts multiple values separated by a pipe character: ' | ' .
149+
Use ? to represent any single character, and * to represent any string.
150+
:type str
151+
152+
@param exclude: Exclude documents whose IDs are exactly <startsWith>+<exclude>.
153+
Accepts multiple values separated by a pipe character: ' | ' .
154+
Use ? to represent any single character, and * to represent any string.
155+
type: str
156+
157+
@param start: number of results to skip.
158+
type: int
159+
160+
@param page_size: maximum number of results to retrieve
161+
type: int
162+
163+
@param metadata_only: specifies if only document metadata should be returned
164+
:type bool
165+
166+
@return: A list of the id or ids we looked for (if they exists)
167+
:rtype: dict
168+
"""
169+
170+
super(GetDocumentsByPrefixCommand, self).__init__(method="GET", is_read_request=True)
171+
172+
self.start_with = start_with
173+
self.start_after = start_after
174+
self.matches = matches
175+
self.exclude = exclude
176+
self.start = start
177+
self.page_size = page_size
178+
self.metadata_only = metadata_only
179+
180+
if self.start_with is None:
181+
raise ValueError("None start_with is not valid")
182+
183+
def create_request(self, server_node):
184+
path = f"docs?startsWith={Utils.quote_key(self.start_with)}"
185+
186+
if self.matches:
187+
path += f"&matches={Utils.quote_key(self.matches)}"
188+
if self.exclude:
189+
path += f"&exclude={Utils.quote_key(self.exclude)}"
190+
if self.start_after:
191+
path += f"&startAfter={Utils.quote_key(self.start_after)}"
192+
if self.start:
193+
path += f"&start={self.start}"
194+
if self.page_size:
195+
path += f"&pageSize={self.page_size}"
196+
if self.metadata_only:
197+
path += "&metadataOnly=true"
198+
199+
self.url = "{0}/databases/{1}/{2}".format(server_node.url, server_node.database, path)
200+
201+
def set_response(self, response):
202+
if response is None:
203+
return
204+
205+
response = response.json()
206+
if "Error" in response:
207+
raise exceptions.ErrorResponseException(response["Error"])
208+
return response
209+
210+
114211
class DeleteDocumentCommand(RavenCommand):
115212
def __init__(self, key, change_vector=None):
116213
super(DeleteDocumentCommand, self).__init__(method="DELETE")

pyravendb/tests/raven_commands_tests/test_get.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ def setUp(self):
88
super(TestGet, self).setUp()
99
put_command = PutDocumentCommand("products/101", {"Name": "test", "@metadata": {}})
1010
put_command2 = PutDocumentCommand("products/10", {"Name": "test", "@metadata": {}})
11+
put_command3 = PutDocumentCommand("products/102", {"Name": "test", "@metadata": {}})
1112
self.requests_executor = self.store.get_request_executor()
1213
self.requests_executor.execute(put_command)
1314
self.requests_executor.execute(put_command2)
15+
self.requests_executor.execute(put_command3)
1416
self.response = self.requests_executor.execute(GetDocumentCommand("products/101"))
1517
self.other_response = self.requests_executor.execute(GetDocumentCommand("products/10"))
18+
self.paged_response = self.requests_executor.execute(GetDocumentCommand("products/102", start=2, page_size=1))
1619

1720
def tearDown(self):
1821
super(TestGet, self).tearDown()
@@ -25,6 +28,10 @@ def test_not_equal(self):
2528
self.assertNotEqual(self.response["Results"][0]["@metadata"]["@id"],
2629
self.other_response["Results"][0]["@metadata"]["@id"])
2730

31+
def test_paging(self):
32+
self.assertEqual(len(self.paged_response["Results"]), 1)
33+
self.assertEqual(self.paged_response["Results"][0]["@metadata"]["@id"], "products/102")
34+
2835
def test_null(self):
2936
self.assertIsNone(self.requests_executor.execute(GetDocumentCommand("product")))
3037

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import unittest
2+
3+
from pyravendb.commands.raven_commands import (
4+
PutDocumentCommand,
5+
GetDocumentsByPrefixCommand,
6+
)
7+
from pyravendb.tests.test_base import TestBase
8+
9+
10+
class TestGetDocumentsByPrefixCommand(TestBase):
11+
def setUp(self):
12+
super(TestGetDocumentsByPrefixCommand, self).setUp()
13+
self.requests_executor = self.store.get_request_executor()
14+
self.requests_executor.execute(
15+
PutDocumentCommand("products/MB-200", {"Name": "test", "@metadata": {}})
16+
)
17+
self.requests_executor.execute(
18+
PutDocumentCommand("products/MB-201", {"Name": "test", "@metadata": {}})
19+
)
20+
self.requests_executor.execute(
21+
PutDocumentCommand("products/MB-100", {"Name": "test", "@metadata": {}})
22+
)
23+
self.requests_executor.execute(
24+
PutDocumentCommand("products/MB-101", {"Name": "test", "@metadata": {}})
25+
)
26+
self.requests_executor.execute(
27+
PutDocumentCommand("products/BM-100", {"Name": "test", "@metadata": {}})
28+
)
29+
self.requests_executor.execute(
30+
PutDocumentCommand("products/BM-200", {"Name": "test", "@metadata": {}})
31+
)
32+
33+
def tearDown(self):
34+
super(TestGetDocumentsByPrefixCommand, self).tearDown()
35+
self.delete_all_topology_files()
36+
37+
def test_init_WHEN_start_with_is_empty_THEN_raise(self):
38+
self.assertRaises(ValueError, GetDocumentsByPrefixCommand, None)
39+
40+
def test_start_with(self):
41+
response = self.requests_executor.execute(
42+
GetDocumentsByPrefixCommand("products/MB")
43+
)
44+
self.assertEqual(len(response["Results"]), 4)
45+
46+
def test_matches(self):
47+
response = self.requests_executor.execute(
48+
GetDocumentsByPrefixCommand("products/MB-", matches="2*")
49+
)
50+
self.assertEqual(len(response["Results"]), 2)
51+
52+
def test_excludes(self):
53+
response = self.requests_executor.execute(
54+
GetDocumentsByPrefixCommand("products/BM-", exclude="2*")
55+
)
56+
self.assertEqual(len(response["Results"]), 1)
57+
58+
def test_start_after(self):
59+
response = self.requests_executor.execute(
60+
GetDocumentsByPrefixCommand(
61+
"products/MB-", matches="2*", start_after="products/MB-200"
62+
)
63+
)
64+
self.assertEqual(len(response["Results"]), 1)
65+
66+
def test_page(self):
67+
response = self.requests_executor.execute(
68+
GetDocumentsByPrefixCommand("products/MB", start=1, page_size=2)
69+
)
70+
self.assertEqual(len(response["Results"]), 2)
71+
72+
73+
if __name__ == "__main__":
74+
unittest.main()

0 commit comments

Comments
 (0)