strawberry-graphql 0.233.3__py3-none-any.whl → 0.234.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- strawberry/relay/types.py +36 -71
- strawberry/relay/utils.py +88 -3
- {strawberry_graphql-0.233.3.dist-info → strawberry_graphql-0.234.0.dist-info}/METADATA +1 -1
- {strawberry_graphql-0.233.3.dist-info → strawberry_graphql-0.234.0.dist-info}/RECORD +7 -7
- {strawberry_graphql-0.233.3.dist-info → strawberry_graphql-0.234.0.dist-info}/LICENSE +0 -0
- {strawberry_graphql-0.233.3.dist-info → strawberry_graphql-0.234.0.dist-info}/WHEEL +0 -0
- {strawberry_graphql-0.233.3.dist-info → strawberry_graphql-0.234.0.dist-info}/entry_points.txt +0 -0
strawberry/relay/types.py
CHANGED
@@ -38,7 +38,12 @@ from strawberry.utils.aio import aenumerate, aislice, resolve_awaitable
|
|
38
38
|
from strawberry.utils.inspect import in_async_context
|
39
39
|
from strawberry.utils.typing import eval_type, is_classvar
|
40
40
|
|
41
|
-
from .utils import
|
41
|
+
from .utils import (
|
42
|
+
SliceMetadata,
|
43
|
+
from_base64,
|
44
|
+
should_resolve_list_connection_edges,
|
45
|
+
to_base64,
|
46
|
+
)
|
42
47
|
|
43
48
|
if TYPE_CHECKING:
|
44
49
|
from strawberry.scalars import ID
|
@@ -790,61 +795,13 @@ class ListConnection(Connection[NodeType]):
|
|
790
795
|
https://relay.dev/graphql/connections.htm#sec-Pagination-algorithm
|
791
796
|
|
792
797
|
"""
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
# When the base64 hash doesnt exist, the after_type seems to return
|
801
|
-
# arrayconnEction instead of PREFIX. Let's raise a predictable
|
802
|
-
# instead of "An unknown error occurred."
|
803
|
-
raise TypeError("Argument 'after' contains a non-existing value.")
|
804
|
-
|
805
|
-
start = int(after_parsed) + 1
|
806
|
-
if before:
|
807
|
-
before_type, before_parsed = from_base64(before)
|
808
|
-
if before_type != PREFIX:
|
809
|
-
# When the base64 hash doesnt exist, the after_type seems to return
|
810
|
-
# arrayconnEction instead of PREFIX. Let's raise a predictable
|
811
|
-
# instead of "An unknown error occurred.
|
812
|
-
raise TypeError("Argument 'before' contains a non-existing value.")
|
813
|
-
end = int(before_parsed)
|
814
|
-
|
815
|
-
if isinstance(first, int):
|
816
|
-
if first < 0:
|
817
|
-
raise ValueError("Argument 'first' must be a non-negative integer.")
|
818
|
-
|
819
|
-
if first > max_results:
|
820
|
-
raise ValueError(
|
821
|
-
f"Argument 'first' cannot be higher than {max_results}."
|
822
|
-
)
|
823
|
-
|
824
|
-
if end is not None:
|
825
|
-
start = max(0, end - 1)
|
826
|
-
|
827
|
-
end = start + first
|
828
|
-
if isinstance(last, int):
|
829
|
-
if last < 0:
|
830
|
-
raise ValueError("Argument 'last' must be a non-negative integer.")
|
831
|
-
|
832
|
-
if last > max_results:
|
833
|
-
raise ValueError(
|
834
|
-
f"Argument 'last' cannot be higher than {max_results}."
|
835
|
-
)
|
836
|
-
|
837
|
-
if end is not None:
|
838
|
-
start = max(start, end - last)
|
839
|
-
else:
|
840
|
-
end = sys.maxsize
|
841
|
-
|
842
|
-
if end is None:
|
843
|
-
end = start + max_results
|
844
|
-
|
845
|
-
expected = end - start if end != sys.maxsize else None
|
846
|
-
# Overfetch by 1 to check if we have a next result
|
847
|
-
overfetch = end + 1 if end != sys.maxsize else end
|
798
|
+
slice_metadata = SliceMetadata.from_arguments(
|
799
|
+
info,
|
800
|
+
before=before,
|
801
|
+
after=after,
|
802
|
+
first=first,
|
803
|
+
last=last,
|
804
|
+
)
|
848
805
|
|
849
806
|
type_def = get_object_definition(cls)
|
850
807
|
assert type_def
|
@@ -863,15 +820,17 @@ class ListConnection(Connection[NodeType]):
|
|
863
820
|
try:
|
864
821
|
iterator = cast(
|
865
822
|
Union[AsyncIterator[NodeType], AsyncIterable[NodeType]],
|
866
|
-
cast(Sequence, nodes)[
|
823
|
+
cast(Sequence, nodes)[
|
824
|
+
slice_metadata.start : slice_metadata.overfetch
|
825
|
+
],
|
867
826
|
)
|
868
827
|
except TypeError:
|
869
828
|
# TODO: Why mypy isn't narrowing this based on the if above?
|
870
829
|
assert isinstance(nodes, (AsyncIterator, AsyncIterable))
|
871
830
|
iterator = aislice(
|
872
831
|
nodes,
|
873
|
-
start,
|
874
|
-
overfetch,
|
832
|
+
slice_metadata.start,
|
833
|
+
slice_metadata.overfetch,
|
875
834
|
)
|
876
835
|
|
877
836
|
# The slice above might return an object that now is not async
|
@@ -880,7 +839,7 @@ class ListConnection(Connection[NodeType]):
|
|
880
839
|
edges: List[Edge] = [
|
881
840
|
edge_class.resolve_edge(
|
882
841
|
cls.resolve_node(v, info=info, **kwargs),
|
883
|
-
cursor=start + i,
|
842
|
+
cursor=slice_metadata.start + i,
|
884
843
|
)
|
885
844
|
async for i, v in aenumerate(iterator)
|
886
845
|
]
|
@@ -888,17 +847,20 @@ class ListConnection(Connection[NodeType]):
|
|
888
847
|
edges: List[Edge] = [ # type: ignore[no-redef]
|
889
848
|
edge_class.resolve_edge(
|
890
849
|
cls.resolve_node(v, info=info, **kwargs),
|
891
|
-
cursor=start + i,
|
850
|
+
cursor=slice_metadata.start + i,
|
892
851
|
)
|
893
852
|
for i, v in enumerate(iterator)
|
894
853
|
]
|
895
854
|
|
896
|
-
has_previous_page = start > 0
|
897
|
-
if
|
855
|
+
has_previous_page = slice_metadata.start > 0
|
856
|
+
if (
|
857
|
+
slice_metadata.expected is not None
|
858
|
+
and len(edges) == slice_metadata.expected + 1
|
859
|
+
):
|
898
860
|
# Remove the overfetched result
|
899
861
|
edges = edges[:-1]
|
900
862
|
has_next_page = True
|
901
|
-
elif end == sys.maxsize:
|
863
|
+
elif slice_metadata.end == sys.maxsize:
|
902
864
|
# Last was asked without any after/before
|
903
865
|
assert last is not None
|
904
866
|
original_len = len(edges)
|
@@ -923,14 +885,14 @@ class ListConnection(Connection[NodeType]):
|
|
923
885
|
try:
|
924
886
|
iterator = cast(
|
925
887
|
Union[Iterator[NodeType], Iterable[NodeType]],
|
926
|
-
cast(Sequence, nodes)[start:overfetch],
|
888
|
+
cast(Sequence, nodes)[slice_metadata.start : slice_metadata.overfetch],
|
927
889
|
)
|
928
890
|
except TypeError:
|
929
891
|
assert isinstance(nodes, (Iterable, Iterator))
|
930
892
|
iterator = itertools.islice(
|
931
893
|
nodes,
|
932
|
-
start,
|
933
|
-
overfetch,
|
894
|
+
slice_metadata.start,
|
895
|
+
slice_metadata.overfetch,
|
934
896
|
)
|
935
897
|
|
936
898
|
if not should_resolve_list_connection_edges(info):
|
@@ -947,17 +909,20 @@ class ListConnection(Connection[NodeType]):
|
|
947
909
|
edges = [
|
948
910
|
edge_class.resolve_edge(
|
949
911
|
cls.resolve_node(v, info=info, **kwargs),
|
950
|
-
cursor=start + i,
|
912
|
+
cursor=slice_metadata.start + i,
|
951
913
|
)
|
952
914
|
for i, v in enumerate(iterator)
|
953
915
|
]
|
954
916
|
|
955
|
-
has_previous_page = start > 0
|
956
|
-
if
|
917
|
+
has_previous_page = slice_metadata.start > 0
|
918
|
+
if (
|
919
|
+
slice_metadata.expected is not None
|
920
|
+
and len(edges) == slice_metadata.expected + 1
|
921
|
+
):
|
957
922
|
# Remove the overfetched result
|
958
923
|
edges = edges[:-1]
|
959
924
|
has_next_page = True
|
960
|
-
elif end == sys.maxsize:
|
925
|
+
elif slice_metadata.end == sys.maxsize:
|
961
926
|
# Last was asked without any after/before
|
962
927
|
assert last is not None
|
963
928
|
original_len = len(edges)
|
strawberry/relay/utils.py
CHANGED
@@ -1,11 +1,17 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import base64
|
2
|
-
|
3
|
-
|
4
|
+
import dataclasses
|
5
|
+
import sys
|
6
|
+
from typing import TYPE_CHECKING, Any, Tuple, Union
|
7
|
+
from typing_extensions import Self, assert_never
|
4
8
|
|
5
|
-
from strawberry.types.info import Info
|
6
9
|
from strawberry.types.nodes import InlineFragment, Selection
|
7
10
|
from strawberry.types.types import StrawberryObjectDefinition
|
8
11
|
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from strawberry.types.info import Info
|
14
|
+
|
9
15
|
|
10
16
|
def from_base64(value: str) -> Tuple[str, str]:
|
11
17
|
"""Parse the base64 encoded relay value.
|
@@ -102,3 +108,82 @@ def should_resolve_list_connection_edges(info: Info) -> bool:
|
|
102
108
|
if _check_selection(selection):
|
103
109
|
return True
|
104
110
|
return False
|
111
|
+
|
112
|
+
|
113
|
+
@dataclasses.dataclass
|
114
|
+
class SliceMetadata:
|
115
|
+
start: int
|
116
|
+
end: int
|
117
|
+
expected: int | None
|
118
|
+
|
119
|
+
@property
|
120
|
+
def overfetch(self) -> int:
|
121
|
+
# Overfetch by 1 to check if we have a next result
|
122
|
+
return self.end + 1 if self.end != sys.maxsize else self.end
|
123
|
+
|
124
|
+
@classmethod
|
125
|
+
def from_arguments(
|
126
|
+
cls,
|
127
|
+
info: Info,
|
128
|
+
*,
|
129
|
+
before: str | None = None,
|
130
|
+
after: str | None = None,
|
131
|
+
first: int | None = None,
|
132
|
+
last: int | None = None,
|
133
|
+
) -> Self:
|
134
|
+
"""Get the slice metadata to use on ListConnection."""
|
135
|
+
from strawberry.relay.types import PREFIX
|
136
|
+
|
137
|
+
max_results = info.schema.config.relay_max_results
|
138
|
+
start = 0
|
139
|
+
end: int | None = None
|
140
|
+
|
141
|
+
if after:
|
142
|
+
after_type, after_parsed = from_base64(after)
|
143
|
+
if after_type != PREFIX:
|
144
|
+
raise TypeError("Argument 'after' contains a non-existing value.")
|
145
|
+
|
146
|
+
start = int(after_parsed) + 1
|
147
|
+
if before:
|
148
|
+
before_type, before_parsed = from_base64(before)
|
149
|
+
if before_type != PREFIX:
|
150
|
+
raise TypeError("Argument 'before' contains a non-existing value.")
|
151
|
+
end = int(before_parsed)
|
152
|
+
|
153
|
+
if isinstance(first, int):
|
154
|
+
if first < 0:
|
155
|
+
raise ValueError("Argument 'first' must be a non-negative integer.")
|
156
|
+
|
157
|
+
if first > max_results:
|
158
|
+
raise ValueError(
|
159
|
+
f"Argument 'first' cannot be higher than {max_results}."
|
160
|
+
)
|
161
|
+
|
162
|
+
if end is not None:
|
163
|
+
start = max(0, end - 1)
|
164
|
+
|
165
|
+
end = start + first
|
166
|
+
if isinstance(last, int):
|
167
|
+
if last < 0:
|
168
|
+
raise ValueError("Argument 'last' must be a non-negative integer.")
|
169
|
+
|
170
|
+
if last > max_results:
|
171
|
+
raise ValueError(
|
172
|
+
f"Argument 'last' cannot be higher than {max_results}."
|
173
|
+
)
|
174
|
+
|
175
|
+
if end is not None:
|
176
|
+
start = max(start, end - last)
|
177
|
+
else:
|
178
|
+
end = sys.maxsize
|
179
|
+
|
180
|
+
if end is None:
|
181
|
+
end = start + max_results
|
182
|
+
|
183
|
+
expected = end - start if end != sys.maxsize else None
|
184
|
+
|
185
|
+
return cls(
|
186
|
+
start=start,
|
187
|
+
end=end,
|
188
|
+
expected=expected,
|
189
|
+
)
|
@@ -174,8 +174,8 @@ strawberry/quart/views.py,sha256=SDUaDX7bPKsv8PziMPb0C3nH6vre-Q3bhzSQp4uPjbY,340
|
|
174
174
|
strawberry/relay/__init__.py,sha256=Vi4btvA_g6Cj9Tk_F9GCSegapIf2WqkOWV8y3P0cTCs,553
|
175
175
|
strawberry/relay/exceptions.py,sha256=b7sU2MhHVWJOfq27lvqdFcqBZ5P_JWk41JWRjtP-AOI,3916
|
176
176
|
strawberry/relay/fields.py,sha256=4V8jhPDECx0hPqtc0ZsNxvmhRYMf5whD_686O2-6_Dc,15934
|
177
|
-
strawberry/relay/types.py,sha256=
|
178
|
-
strawberry/relay/utils.py,sha256=
|
177
|
+
strawberry/relay/types.py,sha256=R7hCsLX0qR3pa4URLbtOeaMHr9EQwbpz-Vedr_PHCrU,29242
|
178
|
+
strawberry/relay/utils.py,sha256=44zl0_iXZElQ35YQkguccCGandKTovqiU5tpve9Ceb4,5575
|
179
179
|
strawberry/resolvers.py,sha256=g7_g3jmXszziGydY1UG6IItf9s6B1lGLUCnwW1kb8U0,224
|
180
180
|
strawberry/sanic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
181
181
|
strawberry/sanic/context.py,sha256=qfoj8QMaAiWbCQFAdm2KPPJGNc7ilXeKAl5z0XJ2nzo,805
|
@@ -245,8 +245,8 @@ strawberry/utils/logging.py,sha256=flS7hV0JiIOEdXcrIjda4WyIWix86cpHHFNJL8gl1y4,7
|
|
245
245
|
strawberry/utils/operation.py,sha256=Um-tBCPl3_bVFN2Ph7o1mnrxfxBes4HFCj6T0x4kZxE,1135
|
246
246
|
strawberry/utils/str_converters.py,sha256=avIgPVLg98vZH9mA2lhzVdyyjqzLsK2NdBw9mJQ02Xk,813
|
247
247
|
strawberry/utils/typing.py,sha256=G92wuT2WhEGQrwjek_On2K8l0nyVFtBW3P7I_cfjG-8,13870
|
248
|
-
strawberry_graphql-0.
|
249
|
-
strawberry_graphql-0.
|
250
|
-
strawberry_graphql-0.
|
251
|
-
strawberry_graphql-0.
|
252
|
-
strawberry_graphql-0.
|
248
|
+
strawberry_graphql-0.234.0.dist-info/LICENSE,sha256=m-XnIVUKqlG_AWnfi9NReh9JfKhYOB-gJfKE45WM1W8,1072
|
249
|
+
strawberry_graphql-0.234.0.dist-info/METADATA,sha256=b_WjywAyZWmvXZfQmNglw490pT-d-tEXYnmpAk51PWQ,7821
|
250
|
+
strawberry_graphql-0.234.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
251
|
+
strawberry_graphql-0.234.0.dist-info/entry_points.txt,sha256=Nk7-aT3_uEwCgyqtHESV9H6Mc31cK-VAvhnQNTzTb4k,49
|
252
|
+
strawberry_graphql-0.234.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
{strawberry_graphql-0.233.3.dist-info → strawberry_graphql-0.234.0.dist-info}/entry_points.txt
RENAMED
File without changes
|