@@ -318,76 +318,14 @@ def all(self):
318318 users .extend (response ["Items" ])
319319 return users
320320
321- def _last_evaluated_to_friendly (self , last_evaluated_keys ):
322- """
323- Received from Dynamo, and serialized into something our clients can
324- understand (or rather, use: this _should_ be an opaque token to
325- clients).
326-
327- When we're paginating through Dynamo, each segment returns a
328- `LastEvaluatedKey`, which we need to specify as `ExclusiveStartKey` in
329- subsequent requests. These `ExclusiveStartKey` is segment-specific,
330- hence the care here to serialize these in the order returned.
331-
332- * `None`, indicating that we've completely finished, there are no more
333- results any segment can return;
334- * `list[Optional[Any]]`, indicating that _some_ segments have results
335- left.
336-
337- Our clients' pagination logic (at least as seen by various publishers),
338- will consider the query over once we return `None`.
339- """
340- if not last_evaluated_keys :
341- return None
342- next_page = []
343- for last_evaluated_key in last_evaluated_keys :
344- # A signal that the segment is done scanning.
345- if last_evaluated_key is None :
346- id = ""
347- else :
348- id = last_evaluated_key ["id" ]["S" ]
349- next_page .append (id )
350- # If there are at all any segments left with work, then continue.
351- if any (next_page ):
352- next_page_raw = "," .join (next_page )
353- return urllib .parse .quote (next_page_raw )
354- else :
355- return None
356-
357- def _next_page_to_dynamodb (self , next_page_raw ):
358- """
359- Received from _clients_, and deserialized into something our parallel
360- Dynamo code understands.
361-
362- A complication here is that we can't reuse `None`, since that would
363- cause a segment to start from the beginning. So, we use a sentinel
364- value of `"done"` to signal to the parallel Dynamo code that we should
365- skip this segment.
366-
367- When Dynamo returns `None`, that means _all_ segments are done. If it
368- returns a `list[Optional[Any]]`, that means that we can still make
369- progress on some segments.
370- """
371- if not next_page_raw :
372- return None
373- next_page = urllib .parse .unquote (next_page_raw )
374- exclusive_start_keys = []
375- for last_evaluated_key in next_page .split ("," ):
376- if last_evaluated_key == "" :
377- id = "done"
378- else :
379- id = {"id" : {"S" : last_evaluated_key }}
380- exclusive_start_keys .append (id )
381- return exclusive_start_keys
382-
383321 def all_filtered (self , connection_method = None , active = None , next_page = None ):
384322 """
385323 @query_filter str login_method
386324 Returns a dict of all users filtered by query_filter
387325 """
388326
389327 projection_expression = "id, primary_email, user_uuid, active"
390- next_page = self . _next_page_to_dynamodb (next_page )
328+ next_page = next_page_to_dynamodb (next_page )
391329
392330 if connection_method :
393331 logger .debug ("No active filter passed. Assuming we need all users." )
@@ -407,7 +345,7 @@ def all_filtered(self, connection_method=None, active=None, next_page=None):
407345 projection_expression = projection_expression ,
408346 exclusive_start_keys = next_page ,
409347 )
410- return dict (users = response ["users" ], nextPage = self . _last_evaluated_to_friendly (response .get ("nextPage" )))
348+ return dict (users = response ["users" ], nextPage = last_evaluated_to_friendly (response .get ("nextPage" )))
411349
412350 def find_or_create (self , user_profile ):
413351 profilev2 = json .loads (user_profile ["profile" ])
@@ -684,3 +622,67 @@ def find_or_create(self, user_profile):
684622 else :
685623 result = self .create (user_profile ).user_id
686624 return result
625+
626+
627+ def last_evaluated_to_friendly (last_evaluated_keys ):
628+ """
629+ Received from Dynamo, and serialized into something our clients can
630+ understand (or rather, use: this _should_ be an opaque token to
631+ clients).
632+
633+ When we're paginating through Dynamo, each segment returns a
634+ `LastEvaluatedKey`, which we need to specify as `ExclusiveStartKey` in
635+ subsequent requests. These `ExclusiveStartKey` is segment-specific,
636+ hence the care here to serialize these in the order returned.
637+
638+ * `None`, indicating that we've completely finished, there are no more
639+ results any segment can return;
640+ * `list[Optional[Any]]`, indicating that _some_ segments have results
641+ left.
642+
643+ Our clients' pagination logic (at least as seen by various publishers),
644+ will consider the query over once we return `None`.
645+ """
646+ if not last_evaluated_keys :
647+ return None
648+ next_page = []
649+ for last_evaluated_key in last_evaluated_keys :
650+ # A signal that the segment is done scanning.
651+ if last_evaluated_key is None :
652+ id = ""
653+ else :
654+ id = last_evaluated_key ["id" ]["S" ]
655+ next_page .append (id )
656+ # If there are at all any segments left with work, then continue.
657+ if any (next_page ):
658+ next_page_raw = "," .join (next_page )
659+ return urllib .parse .quote (next_page_raw )
660+ else :
661+ return None
662+
663+
664+ def next_page_to_dynamodb (next_page ):
665+ """
666+ Received from _clients_, and deserialized into something our parallel
667+ Dynamo code understands.
668+
669+ A complication here is that we can't reuse `None`, since that would
670+ cause a segment to start from the beginning. So, we use a sentinel
671+ value of `""` to signal to the parallel Dynamo code that we should
672+ skip this segment.
673+
674+ When Dynamo returns `None`, that means _all_ segments are done. If it
675+ returns a `list[Optional[Any]]`, that means that we can still make
676+ progress on some segments.
677+ """
678+ if not next_page :
679+ return None
680+ next_page_unquoted = urllib .parse .unquote (next_page )
681+ exclusive_start_keys = []
682+ for last_evaluated_key in next_page_unquoted .split ("," ):
683+ if last_evaluated_key == "" :
684+ id = None
685+ else :
686+ id = {"id" : {"S" : last_evaluated_key }}
687+ exclusive_start_keys .append (id )
688+ return exclusive_start_keys
0 commit comments