Skip to content

Commit 86d57e3

Browse files
committed
fix: make max sub-collection depth configurable
1 parent d213c75 commit 86d57e3

3 files changed

Lines changed: 27 additions & 5 deletions

File tree

nitric/api/const.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# The maximum number of parent collections a sub-collection can have.
2+
# This is implemented in the Membrane, but reinforced here for immediate exceptions without a server connection.
3+
MAX_SUB_COLLECTION_DEPTH = 1

nitric/api/documents.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from enum import Enum
55
from typing import List, AsyncIterator, Union, Any, Tuple
66

7+
from nitric.api.const import MAX_SUB_COLLECTION_DEPTH
78
from nitric.proto.nitric.document.v1 import (
89
DocumentServiceStub,
910
Collection as CollectionMessage,
@@ -15,6 +16,12 @@
1516
from nitric.utils import new_default_channel, _dict_from_struct, _struct_from_dict
1617

1718

19+
class CollectionDepthException(Exception):
20+
"""Exception when the max depth of document sub-collections is exceeded."""
21+
22+
pass
23+
24+
1825
@dataclass(frozen=True, order=True)
1926
class DocumentRef:
2027
"""A reference to a document in a collection."""
@@ -31,9 +38,13 @@ def collection(self, name: str) -> CollectionRef:
3138
e.g. Documents().collection('a').doc('b').collection('c').doc('d') is valid,
3239
Documents().collection('a').doc('b').collection('c').doc('d').collection('e') is invalid (1 level too deep).
3340
"""
34-
if self.parent.is_sub_collection():
35-
# Collection nesting is currently unsupported, but may be included in a future enhancement.
36-
raise Exception("Currently, sub-collections may only be nested 1 deep")
41+
current_depth = self.parent.sub_collection_depth()
42+
if current_depth >= MAX_SUB_COLLECTION_DEPTH:
43+
# Collection nesting is only supported to a maximum depth.
44+
raise CollectionDepthException(
45+
f"sub-collections supported to a depth of {MAX_SUB_COLLECTION_DEPTH}, "
46+
f"attempted to create new collection with depth {current_depth + 1}"
47+
)
3748
return CollectionRef(_documents=self._documents, name=name, parent=self)
3849

3950
async def get(self) -> Document:
@@ -121,6 +132,12 @@ def query(
121132
expressions=[expressions] if isinstance(expressions, Expression) else expressions,
122133
)
123134

135+
def sub_collection_depth(self) -> int:
136+
if not self.is_sub_collection():
137+
return 0
138+
else:
139+
return self.parent.parent.sub_collection_depth() + 1
140+
124141
def is_sub_collection(self):
125142
"""Return True if this collection is a sub-collection of a document in another collection."""
126143
return self.parent is not None
@@ -302,7 +319,7 @@ def where(
302319
self,
303320
*expressions: Union[
304321
Expression, List[Expression], Union[str, Operator, int, bool, Tuple[str, Union[str, Operator], Any]]
305-
]
322+
],
306323
) -> QueryBuilder:
307324
"""
308325
Add a filter expression to the query.

tests/api/test_documents.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ async def test_nested_subcollections_fail(self):
186186
with pytest.raises(Exception) as e:
187187
Documents().collection("a").doc("b").collection("c").doc("d").collection("should-fail")
188188

189-
self.assertIn("sub-collections may only be nested 1 deep", str(e.value))
189+
self.assertIn(
190+
"sub-collections supported to a depth of 1, attempted to create new collection with depth 2", str(e.value)
191+
)
190192

191193
async def test_collection_query_fetch(self):
192194
mock_query = AsyncMock()

0 commit comments

Comments
 (0)