o
    l>j$                     @  s   d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZmZmZ edd	G d
d dZeG dd deZG dd dZG dd dZdddddZdS )z4Persistent sync state for the modern Photos service.    )annotationsN)	dataclass)Path)TracebackType)IteratorProtocolruntime_checkableT)slotsc                   @  sN   e Zd ZU dZded< ded< ded< dZded< dZd	ed
< dZd	ed< dS )SyncedPhotoResourcez=One locally materialized resource tracked by the sync engine.strasset_idresource_keyrelative_pathNz
int | Nonesize
str | Nonechecksumdownloaded_at)__name__
__module____qualname____doc____annotations__r   r   r    r   r   \/home/thesage/.local/lib/python3.10/site-packages/pyicloud/services/photos_cloudkit/state.pyr
      s   
 r
   c                   @  sj   e Zd ZdZd(ddZd)ddZd*ddZd+ddZd,ddZd-ddZ	d.dd Z
d/d"d#Zd0d%d&Zd'S )1PhotoSyncStatez>Backend interface for persisted or ephemeral photo sync state.return'PhotoSyncState'c                 C     dS )z4Open the backend and return the active state object.Nr   selfr   r   r   	__enter__       zPhotoSyncState.__enter__exc_typetype[BaseException] | NoneexcBaseException | NonetbTracebackType | NoneNonec                 C  r   )zClose the backend if needed.Nr   r   r"   r$   r&   r   r   r   __exit__   r!   zPhotoSyncState.__exit__r   c                 C  r   )7Return the last successful sync cursor for this target.Nr   r   r   r   r   get_sync_cursor'   r!   zPhotoSyncState.get_sync_cursorvaluec                 C  r   )8Persist the last successful sync cursor for this target.Nr   r   r-   r   r   r   set_sync_cursor*   r!   zPhotoSyncState.set_sync_cursorr   r   r   SyncedPhotoResource | Nonec                 C  r   )zLook up one tracked resource.Nr   r   r   r   r   r   r   get_resource-   r!   zPhotoSyncState.get_resourceresourcer
   c                 C  r   )z'Insert or replace one tracked resource.Nr   r   r4   r   r   r   upsert_resource2   r!   zPhotoSyncState.upsert_resourcec                 C  r   )z.Delete one tracked resource from the manifest.Nr   r2   r   r   r   delete_resource5   r!   zPhotoSyncState.delete_resourceIterator[SyncedPhotoResource]c                 C  r   )zIterate all tracked resources.Nr   r   r   r   r   iter_resources8   r!   zPhotoSyncState.iter_resourcesintc                 C  r   )z'Return the number of tracked resources.Nr   r   r   r   r   resource_count;   r!   zPhotoSyncState.resource_countN)r   r   )r"   r#   r$   r%   r&   r'   r   r(   r   r   r-   r   r   r(   r   r   r   r   r   r1   r4   r
   r   r(   r   r   r   r   r   r(   r   r8   r   r:   )r   r   r   r   r    r*   r,   r0   r3   r6   r7   r9   r;   r   r   r   r   r      s    







r   c                   @  s   e Zd ZdZd-ddZd.d	d
Zd/ddZd/ddZd/ddZe	d0ddZ
d1ddZd2ddZd3ddZd4d"d#Zd5d$d%Zd6d'd(Zd7d*d+Zd,S )8SQLitePhotoSyncStatezDSQLite-backed manifest and sync-token store for a photo sync target.db_pathr   r   r(   c                 C  s   || _ d | _d S N)rD   _conn)r   rD   r   r   r   __init__B      
zSQLitePhotoSyncState.__init__'SQLitePhotoSyncState'c                 C  s   |    | S rE   )openr   r   r   r   r    F   s   zSQLitePhotoSyncState.__enter__c                 C  s   |    d S rE   )closer)   r   r   r   r*   J   s   zSQLitePhotoSyncState.__exit__c                 C  sj   | j durdS | jjjddd t| j| _ tj| j _| j d | j d | j 	d | j 
  dS )z3Open the SQLite database and initialize the schema.NT)parentsexist_okzPRAGMA journal_mode=WALzPRAGMA foreign_keys=ONa  
            CREATE TABLE IF NOT EXISTS sync_meta (
                key TEXT PRIMARY KEY,
                value TEXT
            );

            CREATE TABLE IF NOT EXISTS synced_resources (
                asset_id TEXT NOT NULL,
                resource_key TEXT NOT NULL,
                relative_path TEXT NOT NULL,
                size INTEGER,
                checksum TEXT,
                downloaded_at TEXT,
                PRIMARY KEY (asset_id, resource_key)
            );
            )rF   rD   parentmkdirsqlite3connectRowrow_factoryexecuteexecutescriptcommitr   r   r   r   rJ   M   s   

zSQLitePhotoSyncState.openc                 C  s"   | j du rdS | j   d| _ dS )z*Close the SQLite connection if it is open.N)rF   rK   r   r   r   r   rK   k   s   


zSQLitePhotoSyncState.closesqlite3.Connectionc                 C  s&   | j du r	|   | j dusJ | j S )z$Return the active SQLite connection.N)rF   rJ   r   r   r   r   conns   s   
zSQLitePhotoSyncState.connr   c                 C  s&   | j dd }|du rdS |d S )r+   z)SELECT value FROM sync_meta WHERE key = ?sync_cursorNr-   )rX   rT   fetchoner   rowr   r   r   r,   |   s   z$SQLitePhotoSyncState.get_sync_cursorr-   c                 C  s8   |du r| j dd n	| j dd|f | j   dS )r.   Nz#DELETE FROM sync_meta WHERE key = ?rY   z
                INSERT INTO sync_meta(key, value)
                VALUES(?, ?)
                ON CONFLICT(key) DO UPDATE SET value = excluded.value
                rZ   rX   rT   rV   r/   r   r   r   r0      s   z$SQLitePhotoSyncState.set_sync_cursorr   r   r   r1   c                 C  sN   | j d||f }|du rdS t|d |d |d |d |d |d d	S )
z:Look up a previously synced resource by asset/version key.z
            SELECT asset_id, resource_key, relative_path, size, checksum, downloaded_at
            FROM synced_resources
            WHERE asset_id = ? AND resource_key = ?
            Nr   r   r   r   r   r   r   r   r   r   r   r   )rX   rT   r[   r
   )r   r   r   r]   r   r   r   r3      s    z!SQLitePhotoSyncState.get_resourcer4   r
   c              	   C  s4   | j d|j|j|j|j|j|jf | j   dS )z=Persist the latest known local state for one synced resource.a  
            INSERT INTO synced_resources(
                asset_id, resource_key, relative_path, size, checksum, downloaded_at
            )
            VALUES(?, ?, ?, ?, ?, ?)
            ON CONFLICT(asset_id, resource_key) DO UPDATE SET
                relative_path = excluded.relative_path,
                size = excluded.size,
                checksum = excluded.checksum,
                downloaded_at = excluded.downloaded_at
            N)	rX   rT   r   r   r   r   r   r   rV   r5   r   r   r   r6      s   z$SQLitePhotoSyncState.upsert_resourcec                 C  s    | j d||f | j   dS )z-Forget one synced resource from the manifest.zj
            DELETE FROM synced_resources
            WHERE asset_id = ? AND resource_key = ?
            Nr^   r2   r   r   r   r7      s
   z$SQLitePhotoSyncState.delete_resourcer8   c              	   c  sJ    | j d}|D ]}t|d |d |d |d |d |d dV  q	d	S )
z3Iterate all tracked resources for this sync target.z
            SELECT asset_id, resource_key, relative_path, size, checksum, downloaded_at
            FROM synced_resources
            ORDER BY relative_path
            r   r   r   r   r   r   r_   N)rX   rT   r
   )r   rowsr]   r   r   r   r9      s   
z#SQLitePhotoSyncState.iter_resourcesr:   c                 C  s(   | j d }|du rdS t|d S )z7Return the number of tracked resources in the manifest.z.SELECT COUNT(*) AS count FROM synced_resourcesNr   count)rX   rT   r[   r:   r\   r   r   r   r;      s   z#SQLitePhotoSyncState.resource_countN)rD   r   r   r(   )r   rI   r   r(   )r   rW   r<   r=   r>   r?   r@   rA   rB   )r   r   r   r   rG   r    r*   rJ   rK   propertyrX   r,   r0   r3   r6   r7   r9   r;   r   r   r   r   rC   ?   s     






	



rC   c                   @  st   e Zd ZdZd$ddZd%ddZd$d	d
Zd&ddZd'ddZd(ddZ	d)ddZ
d*ddZd+ddZd,d!d"Zd#S )-MemoryPhotoSyncStatez3Ephemeral manifest used for preview-only sync runs.r   r(   c                 C  s   d | _ i | _d S rE   )_cursor
_resourcesr   r   r   r   rG      rH   zMemoryPhotoSyncState.__init__'MemoryPhotoSyncState'c                 C  s   | S rE   r   r   r   r   r   r          zMemoryPhotoSyncState.__enter__c                 C  s   d S rE   r   r)   r   r   r   r*      rh   zMemoryPhotoSyncState.__exit__r   c                 C  s   | j S )z)Return the stored preview cursor, if any.re   r   r   r   r   r,      s   z$MemoryPhotoSyncState.get_sync_cursorr-   c                 C  s
   || _ dS )z!Store a preview cursor in memory.Nri   r/   r   r   r   r0        
z$MemoryPhotoSyncState.set_sync_cursorr   r   r   r1   c                 C  s   | j ||fS )zLook up a preview resource row.)rf   getr2   r   r   r   r3     s   z!MemoryPhotoSyncState.get_resourcer4   r
   c                 C  s   || j |j|jf< dS )zStore a preview resource row.N)rf   r   r   r5   r   r   r   r6        z$MemoryPhotoSyncState.upsert_resourcec                 C  s   | j ||fd dS )zDelete a preview resource row.N)rf   popr2   r   r   r   r7     rl   z$MemoryPhotoSyncState.delete_resourcer8   c                 c  s    | j  E dH  dS )zIterate preview resource rows.N)rf   valuesr   r   r   r   r9     s   z#MemoryPhotoSyncState.iter_resourcesr:   c                 C  s
   t | jS )z+Return the number of preview manifest rows.)lenrf   r   r   r   r   r;     rj   z#MemoryPhotoSyncState.resource_countNrb   )r   rg   r<   r=   r>   r?   r@   rA   rB   )r   r   r   r   rG   r    r*   r,   r0   r3   r6   r7   r9   r;   r   r   r   r   rd      s    








rd   F)	ephemeralrD   r   rp   boolr   c                C  s   |rt  S t| S )z>Return the appropriate sync-state backend for one sync target.)rd   rC   )rD   rp   r   r   r   create_photo_sync_state#  s   rr   )rD   r   rp   rq   r   r   )r   
__future__r   rP   dataclassesr   pathlibr   typesr   typingr   r   r   r
   r   rC   rd   rr   r   r   r   r   <module>   s     & 26