88from typing import Type
99
1010from django .core .serializers .json import DjangoJSONEncoder
11- from django .db .models import Q
1211
1312from morango .models .certificates import Filter
1413from morango .models .core import DatabaseMaxCounter
2120from morango .registry import syncable_models
2221from morango .sync .stream .core import Buffer
2322from morango .sync .stream .core import Sink
24- from morango .sync .stream .core import Source
2523from morango .sync .stream .core import Transform
2624from morango .sync .stream .core import Unbuffer
25+ from morango .sync .stream .source import MorangoSource
26+ from morango .sync .stream .source import SourceTask
2727from morango .utils import self_referential_fk
2828
2929logger = logging .getLogger (__name__ )
3030
3131
32- class SerializeTask (object ):
32+ class SerializeTask (SourceTask ):
3333 """Carrier class for providing context through the pipeline"""
3434
3535 __slots__ = ("model" , "obj" , "store" , "counter" )
@@ -40,6 +40,10 @@ def __init__(self, model: Type[SyncableModel], obj: SyncableModel):
4040 self .store : Optional [Store ] = None
4141 self .counter : Optional [RecordMaxCounter ] = None
4242
43+ @property
44+ def id (self ) -> str :
45+ return self .obj .id
46+
4347 @property
4448 def is_store_update (self ):
4549 return self .store is not None and not self .store ._state .adding
@@ -59,59 +63,22 @@ def self_referential_fk(self) -> Optional[str]:
5963 return self_referential_fk (self .model )
6064
6165
62- class AppModelSource (Source [SerializeTask ]):
66+ class AppModelSource (MorangoSource [SerializeTask ]):
6367 """
6468 Yields ``SerializeTask`` objects for every syncable-model record that matches the
6569 optional *sync_filter*.
6670 """
6771
68- def __init__ (
69- self ,
70- profile : str ,
71- sync_filter : Optional [Filter ] = None ,
72- dirty_only : bool = True ,
73- partition_order : str = "asc" ,
74- ):
75- """
76- :param profile: The Morango model profile
77- :param sync_filter: The Filter object for this sync
78- :param dirty_only: Whether to filter on dirty records only
79- :param partition_order: Controls how the filter specificity is applied, "asc" or "desc"
80- """
81- self .profile = profile
82- self .sync_filter = sync_filter
83- self .dirty_only = dirty_only
84- self .partition_order = partition_order
85- self ._seen = set ()
86-
87- def prefix_conditions (self ) -> Generator [Optional [Q ], None , None ]:
88- if self .sync_filter is None :
89- # yield None once, so we do one query without a partition filter (everything)
90- yield None
91- else :
92- partitions_prefixes = [str (prefix ) for prefix in self .sync_filter ]
93- partition_iterator = sorted (
94- partitions_prefixes ,
95- reverse = self .partition_order == "desc" ,
96- )
97-
98- for prefix in partition_iterator :
99- yield Q (_morango_partition__startswith = prefix )
100-
101- def stream (self ) -> Generator [SerializeTask , None , None ]:
102- for partition_condition in self .prefix_conditions ():
103- for qs in syncable_models .get_model_querysets (self .profile ):
104- if partition_condition is not None :
105- qs = qs .filter (partition_condition )
106- if self .dirty_only :
107- qs = qs .filter (_morango_dirty_bit = True )
108- for obj in qs .iterator ():
109- # partition filtering could result in overlaps, and since we're walking
110- # through the partitions one by one, we should avoid duplicates. Morango
111- # syncable models have unique IDs across the entire profile
112- if obj .id not in self ._seen :
113- self ._seen .add (obj .id )
114- yield SerializeTask (qs .model , obj )
72+ def stream_for_filter (
73+ self , partition_condition : Optional [str ]
74+ ) -> Generator [SerializeTask , None , None ]:
75+ for qs in syncable_models .get_model_querysets (self .profile ):
76+ if partition_condition is not None :
77+ qs = qs .filter (_morango_partition__startswith = partition_condition )
78+ if self .dirty_only :
79+ qs = qs .filter (_morango_dirty_bit = True )
80+ for obj in qs .iterator ():
81+ yield SerializeTask (qs .model , obj )
11582
11683
11784class StoreLookup (Transform [List [SerializeTask ]]):
0 commit comments