
    ג[i{(                     H    d Z ddlmZmZmZmZ ddlmZ  G d d          ZdS )aC  
Schema Manager Service

This module provides manual schema evolution capabilities for MongoDB collections.
Users can add new fields to collections through the UI with explicit confirmation.

Key principles:
- Field addition is MANUAL ONLY (user-initiated)
- No automatic schema changes
- No field deletion or renaming
- Operations are idempotent (safe to re-run)
- Existing data is NEVER modified
- New fields default to null

Safety features:
- Check if field exists before adding
- Preview before applying
- Explicit user confirmation required
- updateMany with $exists check
    )ListDictAnyOptional)
Collectionc            
           e Zd ZdZdddddZd Zdedee         fdZdedede	fd	Z
deded
edeeef         fdZdeded
edeeef         fdZdededeeef         fdZdS )SchemaManagerz
    Service for managing MongoDB collection schemas.
    
    Provides safe, manual schema evolution capabilities including
    adding new fields to all documents in a collection.
    N)stringnumberbooleandatec                     || _         dS )z
        Initialize schema manager with MongoDB connection.
        
        Args:
            mongo_service: MongoService instance
        N)mongo)selfmongo_services     3/var/www/html/IGF-ODF-V3/services/schema_manager.py__init__zSchemaManager.__init__*   s     #


    collection_namereturnc                    | j                             |          }|g S 	 ddddiiiddiddd	d
idig}t          |                    |                    }|rXd|d         v rN|d         d         }t	          |          }d|v r+|                    d           |                    dd           |S g S # t          $ r!}t          d| d|            g cY d}~S d}~ww xY w)a/  
        Get list of all fields that exist in a collection.
        
        This scans all documents and returns the union of all field names.
        
        Args:
            collection_name: Name of the collection
            
        Returns:
            Sorted list of unique field names
        Nz$projectfieldsz$objectToArrayz$$ROOTz$unwindz$fieldsz$groupz	$addToSetz	$fields.k)_id
fieldNamesr   r   r   zError getting fields for z: )	r   get_collectionlist	aggregatesortedremoveinsert	Exceptionprint)r   r   
collectionpipelineresultr   es          r   get_existing_fieldsz!SchemaManager.get_existing_fields3   sN    Z..??
 	I#	
  #3X">! y #'2K&@ H" *..x8899F ,&)3 <0F? ,MM%(((MM!U+++I 	 	 	DoDDDDEEEIIIIII	s$   BB2 0B2 2
C<CCC
field_namec                     | j                             |          }|dS 	 |                    |ddii          }|dk    S # t          $ r Y dS w xY w)a"  
        Check if a field exists in any document in the collection.
        
        Args:
            collection_name: Name of the collection
            field_name: Name of the field to check
            
        Returns:
            True if field exists in at least one document
        NF$existsTr   )r   r   count_documentsr!   )r   r   r(   r#   counts        r   field_existszSchemaManager.field_existsi   st     Z..??
 	5	..
Y<M/NOOE19 	 	 	55	s   ? 
AA
field_typec           	         | j                             |          }|dddS || j        vr2ddd                    | j                                                   dS |r|                                sdddS d|v sd	|v rdd
dS |                     ||          r
dd| dddS | j                             |          }|                    |ddii          }d|||| j        |         ||||z
  dS )a  
        Preview what will happen when adding a field.
        
        Shows how many documents will be affected and validates the operation.
        
        Args:
            collection_name: Name of the collection
            field_name: Name of the field to add
            field_type: Type of the field (string, number, boolean, date)
            
        Returns:
            Dictionary with preview information
        NF0Collection not found or not connected to MongoDB)validerrorz$Invalid field type. Must be one of: z, zField name cannot be empty.$z/Field name cannot contain "." or "$" characterszField "z#" already exists in this collectionT)r1   r2   warningr*   )r1   r   r(   r.   default_valuetotal_documentsdocuments_to_updatedocuments_already_have_field)r   r   FIELD_TYPESjoinkeysstripr-   r+   )r   r   r(   r.   r#   
total_docsdocs_to_updates          r   preview_field_additionz$SchemaManager.preview_field_addition   s   & Z..??
 	K   T-- 	d		$JZJ_J_JaJa@b@bdd    	!1!1!3!3 	5   * 	z 1 	J   _j99 	R:RRR   Z//@@
 $33Z)UAS4TUU .$$!-j9)#1,6,G	
 	
 		
r   c                    | j                             |          }|dddS |                     |||          }|                    d          sd|                    dd          dS 	 | j        |         }|                    |ddiid	||ii          }d
||||j        |j        d| d|j         ddS # t          $ r}ddt          |           dcY d}~S d}~ww xY w)a:  
        Add a new field to all documents in a collection.
        
        This operation:
        1. Checks if field already exists
        2. Adds field with null value to documents that don't have it
        3. Does NOT modify documents that already have the field
        4. Is idempotent (safe to run multiple times)
        
        SAFETY GUARANTEES:
        - Only adds field where it doesn't exist ($exists: false)
        - Never overwrites existing values
        - Uses $set with null value
        - Atomic operation per document
        
        Args:
            collection_name: Name of the collection
            field_name: Name of the field to add
            field_type: Type of the field (string, number, boolean, date)
            
        Returns:
            Dictionary with operation results
        NFr0   )successr2   r1   r2   zInvalid field additionr*   z$setTzSuccessfully added field "z" to z
 documents)rB   r   r(   r.   documents_matcheddocuments_modifiedmessagezError adding field: )
r   r   r@   getr:   update_manymatched_countmodified_countr!   str)	r   r   r(   r.   r#   previewr6   r%   r&   s	            r   add_field_to_collectionz%SchemaManager.add_field_to_collection   si   : Z..??
 	 K   --oz:VV{{7## 	  W.FGG  
	 ,Z8M
  ++i/0*m45 F  #2((%+%9&,&;j
jjI^jjj    	 	 	 8A88       	s   (A
B3 3
C=CCCc                 t   | j                             |          }|i S 	 | j                             |          }|                    |ddii          }|                    |di          }|                    |dddi          }|||||dk    rt          ||z  dz  d          nddS # t          $ r i cY S w xY w)	z
        Get statistics about a field in a collection.
        
        Args:
            collection_name: Name of the collection
            field_name: Name of the field
            
        Returns:
            Dictionary with field statistics
        Nr*   T)r*   z$ner   d      )r7   documents_with_fielddocuments_with_nulldocuments_with_valuecoverage_percentage)r   r   r+   roundr!   )r   r   r(   r#   r>   docs_with_fielddocs_with_nulldocs_with_values           r   get_field_statisticsz"SchemaManager.get_field_statistics  s	    Z..??
 	I	33ODDJ(88*yRVFW9XYYO'77T8JKKN(88T:::  O
 $.(7'5(7YcfgYg'nuo
.JS.PST'U'U'Umn    	 	 	III	s   BB( (B76B7)__name__
__module____qualname____doc__r:   r   rJ   r   r'   boolr-   r   r   r@   rL   rX    r   r   r	   r	      sa         	 K# # #43 449 4 4 4 4lC S T    0G
G
 G
 	G

 
c3hG
 G
 G
 G
RHH H 	H
 
c3hH H H HT!C !S !TRUWZRZ^ ! ! ! ! ! !r   r	   N)	r\   typingr   r   r   r   pymongo.collectionr   r	   r^   r   r   <module>ra      s    * - , , , , , , , , , , , ) ) ) ) ) )[ [ [ [ [ [ [ [ [ [r   