o
    i2                     @   s   d Z ddlmZmZmZmZmZmZmZm	Z	 ddl
mZ ddlmZ ddlmZmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ededZededZededZG dd deeeef ZdS )aB  
Base CRUD operations with tenant awareness and permission filtering.

Provides generic CRUD operations that can be inherited by domain-specific CRUD classes.
Supports:
- Tenant-aware filtering (automatic isolation)
- Permission-based filtering (platform/customer admin/user)
- Pagination
- Soft delete
- Batch operations
    )AnyDictGenericListOptionalTypeTypeVarUnion)jsonable_encoder)	BaseModel)and_or_)Session)IntegrityError)Base)User)ConstraintViolationError	ModelType)boundCreateSchemaTypeUpdateSchemaTypec                   @   s  e Zd ZdZdee fddZ	d4dedede	e
 d	e	e fd
dZddddddddededede	e
 de	eeef  de	e ded	ee fddZddddede	e
 de	eeef  d	efddZdddddedede	e de	e ded	efdd Zdd!ded"edeeeeef f ded	ef
d#d$Zd%dd&deded'eded	e	e f
d(d)Zd%dd&ded*ee ded'eded	efd+d,Zde
defd-d.Zdddd/ded0ed1ee dedede	e
 d	ee fd2d3ZdS )5CRUDBasez
    Base CRUD class with generic database operations.

    Type Parameters:
        ModelType: SQLAlchemy model class
        CreateSchemaType: Pydantic schema for creation
        UpdateSchemaType: Pydantic schema for updates
    modelc                 C   s
   || _ dS )zz
        Initialize CRUD object with a SQLAlchemy model.

        Args:
            model: SQLAlchemy model class
        N)r   )selfr    r   7/lsinfo/ai/hellotax_ai/base_platform/./app/crud/base.py__init__&   s   
zCRUDBase.__init__Ndbidcurrent_userreturnc                 C   s4   | | j| jj|k}|r| |||}| S )z
        Get a single record by ID.

        Args:
            db: Database session
            id: Record ID
            current_user: Current user for permission filtering

        Returns:
            Model instance or None if not found
        )queryr   filterr   _apply_permission_filterfirst)r   r   r   r   r!   r   r   r   get/   s   zCRUDBase.getr   d   T)skiplimitr   filtersorder_by
order_descr'   r(   r)   r*   r+   c                C   s  | | j}|r| |||}|rY| D ]C\}	}
t| j|	rXt|
tr1|t| j|		|
}qt|
t
rM|
drM|
drM|t| j|	|
}q|t| j|	|
k}q|rut| j|rut| j|}||ro| n| }nt| jdr|| jj }||| S )a  
        Get multiple records with pagination and filtering.

        Args:
            db: Database session
            skip: Number of records to skip (offset)
            limit: Maximum number of records to return
            current_user: Current user for permission filtering
            filters: Dictionary of field:value filters
            order_by: Field name to order by (default: created_at if exists)
            order_desc: Whether to order descending (default: True)

        Returns:
            List of model instances
        %
created_at)r!   r   r#   itemshasattr
isinstancelistr"   getattrin_str
startswithendswithliker*   descascr-   offsetr(   all)r   r   r'   r(   r   r)   r*   r+   r!   fieldvalueorder_fieldr   r   r   	get_multiH   s$   
zCRUDBase.get_multi)r   r)   c                C   s   | | j}|r| |||}|rY| D ]C\}}t| j|rXt|tr1|t| j|	|}qt|t
rM|drM|drM|t| j||}q|t| j||k}q| S )a  
        Get count of records matching filters.

        Args:
            db: Database session
            current_user: Current user for permission filtering
            filters: Dictionary of field:value filters

        Returns:
            Count of matching records
        r,   )r!   r   r#   r.   r/   r0   r1   r"   r2   r3   r4   r5   r6   r7   count)r   r   r   r)   r!   r<   r=   r   r   r   	get_count   s   
zCRUDBase.get_count)
created_by	tenant_idcommitobj_inrB   rC   rD   c          
   
   C   s   t |}|rt| jdr||d< |durt| jdr||d< | jdi |}|| |rjz|  |  || || || W |S  tyi } z|	  t|dr]t
|jnt
|}	t|	d}~ww |S )a  
        Create a new record.

        Args:
            db: Database session
            obj_in: Pydantic schema with creation data
            created_by: User ID who created the record
            tenant_id: Tenant ID for multi-tenant isolation
            commit: Whether to commit the transaction (default: True)

        Returns:
            Created model instance

        Raises:
            ConstraintViolationError: If database constraint is violated
        rB   NrC   origr   )r
   r/   r   addflushrD   expungerefreshr   rollbackr4   rF   r   )
r   r   rE   rB   rC   rD   obj_in_datadb_objeconstraint_namer   r   r   create   s,   


zCRUDBase.create)rD   rM   c                C   sj   t |}t|tr|}n|jdd}|D ]}||v r"t||||  q|| |r3|  || |S )aJ  
        Update an existing record.

        Args:
            db: Database session
            db_obj: Existing model instance to update
            obj_in: Pydantic schema or dict with update data
            commit: Whether to commit the transaction (default: True)

        Returns:
            Updated model instance
        T)exclude_unset)r
   r0   dict
model_dumpsetattrrG   rD   rJ   )r   r   rM   rE   rD   obj_dataupdate_datar<   r   r   r   update   s   


zCRUDBase.updateF)softrD   rX   c                C   sb   | | j| jj|k }|sdS |r$t| jdr$d|_|| n|| |r/|	  |S )ac  
        Delete a record (hard or soft delete).

        Args:
            db: Database session
            id: Record ID to delete
            soft: Whether to perform soft delete (set is_deleted=True)
            commit: Whether to commit the transaction (default: True)

        Returns:
            Deleted model instance or None if not found
        N
is_deletedT)
r!   r   r"   r   r$   r/   rY   rG   deleterD   )r   r   r   rX   rD   objr   r   r   rZ     s   
zCRUDBase.deleteidsc          	      C   s   | | j| jj|}t| jdr|| jj|k}t| jdr2|jdkr2|| jj|jk}|rDt| jdrD|j	ddidd}n|j
dd}|rP|  |S )a  
        Delete multiple records (batch operation).

        Args:
            db: Database session
            ids: List of record IDs to delete
            tenant_id: Tenant ID for multi-tenant isolation (required)
            current_user: Current user for ownership verification
            soft: Whether to perform soft delete
            commit: Whether to commit the transaction (default: True)

        Returns:
            Number of records deleted
        rC   rB   platform_adminrY   TF)synchronize_session)r!   r   r"   r   r3   r/   rC   rolerB   rW   rZ   rD   )	r   r   r\   rC   r   rX   rD   r!   r@   r   r   r   delete_multi(  s   zCRUDBase.delete_multic                 C   sP   t | jdr|| jjdk}|jdkr|S t | jdr&|| jj|jk}|S )a  
        Apply permission-based filtering to query.

        Filtering rules:
        - platform_admin: See all records
        - Others: See only records from their tenant
        - Automatically filter soft-deleted records

        Args:
            query: SQLAlchemy query object
            current_user: Current user
            db: Database session

        Returns:
            Filtered query object
        rY   Fr]   rC   )r/   r   r"   rY   r_   rC   )r   r!   r   r   r   r   r   r#   V  s   
z!CRUDBase._apply_permission_filter)r'   r(   r   search_termsearch_fieldsc          
      C   s~   | | j}|r| |||}g }|D ]}	t| j|	r+|t| j|	d| d q|r5|t| }|	|
| S )a  
        Search records across multiple fields.

        Args:
            db: Database session
            search_term: Search term
            search_fields: List of field names to search in
            skip: Number of records to skip
            limit: Maximum number of records to return
            current_user: Current user for permission filtering

        Returns:
            List of matching model instances
        r,   )r!   r   r#   r/   appendr2   r7   r"   r   r:   r(   r;   )
r   r   ra   rb   r'   r(   r   r!   search_conditionsr<   r   r   r   searchz  s   zCRUDBase.search)N)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r%   intr   r4   boolr   r?   rA   r   rP   r	   r   rW   rZ   r`   r#   re   r   r   r   r   r      s    	
	

<
*
<
,
-	
.
*	r   N)ri   typingr   r   r   r   r   r   r   r	   fastapi.encodersr
   pydanticr   
sqlalchemyr   r   sqlalchemy.ormr   sqlalchemy.excr   app.models.baser   app.models.userr   app.core.exceptionsr   r   r   r   r   r   r   r   r   <module>   s    (