11from asyncio import gather
2- from dataclasses import dataclass , field
3- from itertools import groupby
2+ from dataclasses import dataclass
3+
4+ from in_memory_db import InMemoryDb
45
56from tgdb .application .ports .heap import Heap
67from tgdb .entities .message import Message
7- from tgdb .entities .row import DeletedRow , MutatedRow , NewRow , Row , RowEffect
8+ from tgdb .entities .row import (
9+ DeletedRow ,
10+ MutatedRow ,
11+ NewRow ,
12+ Row ,
13+ RowEffect ,
14+ )
815from tgdb .entities .transaction import TransactionEffect
9- from tgdb .infrastructure .row_encoding import encoded_row
16+ from tgdb .infrastructure .heap_row_encoding import encoded_heap_row
1017from tgdb .infrastructure .telethon .client_pool import TelegramClientPool
1118from tgdb .infrastructure .telethon .lazy_message_map import LazyMessageMap
1219from tgdb .infrastructure .telethon .mapping import message
1320
1421
1522@dataclass (frozen = True , unsafe_hash = False )
1623class InMemoryHeap (Heap ):
17- _rows : set [Row ] = field ( default_factory = set )
24+ _db : InMemoryDb [Row ]
1825
1926 async def map (self , effect : TransactionEffect ) -> None :
20- for row_operator_effect in effect :
21- match row_operator_effect , row_operator_effect .row in self ._rows :
22- case NewRow (row ) | MutatedRow (row ), _:
23- self ._rows .add (row )
24- case DeletedRow (row ), True :
25- self ._rows .remove (row )
27+ for row_effect in effect :
28+ prevous_row = self ._db .select_one (
29+ lambda row : row .id == row_effect .row_id
30+ )
31+
32+ match row_effect , prevous_row :
33+ case DeletedRow (), Row ():
34+ self ._db .remove (prevous_row )
35+
36+ case NewRow (new_row ), _:
37+ self ._db .insert (new_row )
38+
39+ case MutatedRow (new_row ), Row ():
40+ self ._db .remove (prevous_row )
41+ self ._db .insert (new_row )
42+
43+ case _: ...
44+
45+ async def map_as_duplicate (self , effect : TransactionEffect ) -> None :
46+ for row_effect in effect :
47+ prevous_row = self ._db .select_one (
48+ lambda row : row .id == row_effect .row_id
49+ )
50+
51+ match row_effect , prevous_row :
52+ case DeletedRow (row_id ), Row ():
53+ self ._db .remove (prevous_row )
54+
55+ case NewRow (new_row ) | MutatedRow (new_row ), Row ():
56+ self ._db .remove (prevous_row )
57+ self ._db .insert (new_row )
58+
2659 case _: ...
2760
2861
2962@dataclass (frozen = True )
30- class TelethonHeap (Heap ):
63+ class InTelegramHeap (Heap ):
3164 _pool_to_insert : TelegramClientPool
3265 _pool_to_select : TelegramClientPool
3366 _pool_to_edit : TelegramClientPool
@@ -36,34 +69,41 @@ class TelethonHeap(Heap):
3669 _message_map : LazyMessageMap
3770
3871 async def map (self , transaction_effect : TransactionEffect ) -> None :
39- row_effects_by_row_id = groupby (
40- transaction_effect , key = lambda it : it .row .id
41- )
42-
4372 await gather (* (
44- self ._map_row_effects ( tuple ( row_effects ) )
45- for _ , row_effects in row_effects_by_row_id
73+ self ._map_row_effect ( row_effect , is_duplicate = False )
74+ for row_effect in transaction_effect
4675 ))
4776
48- async def _map_row_effects (self , effect_part : TransactionEffect ) -> None :
49- await gather (* map (self ._map_row_effect , effect_part ))
77+ async def map_as_duplicate (
78+ self , transaction_effect : TransactionEffect
79+ ) -> None :
80+ await gather (* (
81+ self ._map_row_effect (row_effect , is_duplicate = True )
82+ for row_effect in transaction_effect
83+ ))
5084
51- async def _map_row_effect (self , row_effect : RowEffect ) -> None :
85+ async def _map_row_effect (
86+ self , row_effect : RowEffect , * , is_duplicate : bool
87+ ) -> None :
5288 match row_effect :
5389 case NewRow ():
54- await self ._insert (row_effect )
90+ await self ._insert (row_effect , is_duplicate )
5591 case MutatedRow ():
5692 await self ._update (row_effect )
5793 case DeletedRow ():
5894 await self ._delete (row_effect )
5995
60- async def _insert (self , row_effect : NewRow ) -> None :
61- telethon_message = await self ._pool_to_insert ().send_message (
62- self ._heap_id , encoded_row (row_effect .row )
63- )
64- self ._message_map [row_effect .row .schema , row_effect .row .id ] = (
65- message (telethon_message )
96+ async def _insert (self , row_effect : NewRow , is_duplicate : bool ) -> None :
97+ if is_duplicate :
98+ message_ = await self ._message_map [row_effect .row .id ]
99+
100+ if message_ is not None :
101+ return
102+
103+ tg_new_message = await self ._pool_to_insert ().send_message (
104+ self ._heap_id , encoded_heap_row (row_effect .row )
66105 )
106+ self ._message_map [row_effect .row .id ] = message (tg_new_message )
67107
68108 async def _update (self , row_effect : MutatedRow ) -> None :
69109 message = await self ._message (row_effect )
@@ -72,7 +112,7 @@ async def _update(self, row_effect: MutatedRow) -> None:
72112 return
73113
74114 await self ._pool_to_edit (message .author_id ).edit_message (
75- self ._heap_id , message .id , encoded_row (row_effect .row )
115+ self ._heap_id , message .id , encoded_heap_row (row_effect .row )
76116 )
77117
78118 async def _delete (self , row_effect : DeletedRow ) -> None :
@@ -91,4 +131,10 @@ async def _message(
91131 if row_effect .message is not None :
92132 return row_effect .message
93133
94- return await self ._message_map [row_effect .row .schema , row_effect .row .id ]
134+ match row_effect :
135+ case MutatedRow ():
136+ row_id = row_effect .row .id
137+ case DeletedRow ():
138+ row_id = row_effect .row_id
139+
140+ return await self ._message_map [row_id ]
0 commit comments