
    ɯei[^                     4   d dl Z d dlZd dlZd dlmZ d dlmZ d dlmZm	Z	m
Z
mZmZmZ d dlZd dlmZ d dlmZmZmZmZmZ dZdZd	Z G d
 de      Z G d de      Z G d d      Z G d d      Z G d d      Z G d d      Z  G d d      Z! G d d      Z"y)    N)deque)Enum)AnyDictListOptionalTupleUnion)SnowparkClientExceptionMessages)IntegerType
StringTypeStructField
StructTypeVariantType         c                   <    e Zd ZdZdZdZdZed        Zed        Z	y)LineageDirectiona8  
    Directions for tracing the lineage.

    Attributes:
        DOWNSTREAM (str): Represents the downstream direction in lineage tracing.
        UPSTREAM (str): Represents the upstream direction in lineage tracing.
        BOTH (str): Represents both upstream and downstream direction in lineage tracing.
    
downstreamupstreambothc                 @    | D cg c]  }|j                    c}S c c}w Nvalueclsmembers     \/var/www/html/glpi_dashboard/venv/lib/python3.12/site-packages/snowflake/snowpark/lineage.pyvalueszLineageDirection.values)       +.////   c                 n    | D ]  }|j                   |k(  s|c S  t        d| j                   d| d      )N'z' enum not found for ')r   
ValueError__name__)r   r   r   s      r    value_ofzLineageDirection.value_of-   sE     	OF||u$	O q.DUG1MNN    N)
r'   
__module____qualname____doc__
DOWNSTREAMUPSTREAMBOTHclassmethodr!   r(    r)   r    r   r      s@     JHD0 0 O Or)   r   c                   (    e Zd ZdZdZdZed        Zy)	_EdgeTypez-
    Types of edges for lineage tracing.
    DATA_LINEAGEOBJECT_DEPENDENCYc                 @    | D cg c]  }|j                    c}S c c}w r   r   r   s     r    r!   z_EdgeType.values>   r"   r#   N)r'   r*   r+   r,   r4   r5   r0   r!   r1   r)   r    r3   r3   6   s&     "L+0 0r)   r3   c            
       l    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZdZdZeeeeee	e
eeeg
Zy)_ObjectFieldz_
    Defines static fields used to reference object properties in DGQL query and response.
    domainrefinedDomain
userDomainname
propertiesschemadbstatus	createdOn
parentName
ParentNameversionidparentIdParentId	tableTypetypeN)r'   r*   r+   r,   DOMAINREFINED_DOMAINUSER_DOMAINNAME
PROPERTIESSCHEMADBSTATUS
CREATED_ONPARENT_NAMEPARENT_NAME_DEPRECATEDVERSIONID	PARENT_IDPARENT_ID_DEPRECATED
TABLE_TYPETYPEGRAPH_ENTITY_PROPERTIESr1   r)   r    r8   r8   C   s     F$NKDJF	BFJK)G	BI%JD 	

r)   r8   c                   ,    e Zd ZdZdZdZdZdZdZdZ	dZ
y	)
_DGQLFieldszX
    Contains static definitions of field names used in DGQL queries and responses.
    dataVESTOUTINN)r'   r*   r+   r,   DATANODEEDGESOURCETARGETrc   rd   r1   r)   r    r]   r]   i   s,     DDDFF
C	Br)   r]   c                       e Zd ZdZdZdZdZy)_UserDomainzY
    Domains in the user context that logically maps to different snowflake objects.
    FEATURE_VIEWMODELSERVICEN)r'   r*   r+   r,   rl   rm   rn   r1   r)   r    rk   rk   w   s     "LEGr)   rk   c                   ,    e Zd ZdZdZdZdZdZdZdZ	dZ
y	)
_SnowflakeDomainz
    Snowflake object domains relevant for querying lineage.
    Note: This is a subset and does not include all possible domains.
    TABLEMODULEDATASET
EXPERIMENTVIEWCOLUMNSNOWSERVICE_INSTANCEN)r'   r*   r+   r,   rq   rr   rs   rt   ru   rv   rw   r1   r)   r    rp   rp      s-    
 EFGJDF1r)   rp   c                   $   e Zd ZdZdZdZej                  ej                  ej                  ej                  ej                  ej                  iZe	 	 	 	 ddedee   dee   dee   d	ee   d
ee   defd       Zed        Zedededefd       Zy)_DGQLQueryBuilderz3
    Provides methods for building DGQL query.
    z{direction}: {edge_key}(edgeType:[{edge_types}],direction:{dir}){{{source_key} {{{properties}}}, {target_key} {{{properties}}}, properties}}z]{{{nodeKey}({domainKey}: {domain}, {object_key}:"{query_object}"{parent_param}) {{{edges}}}}}Nobject_domainedge_directionsobject_name	object_idobject_version	parent_idreturnc                 4   |r|s|s|st        d      dj                  t        j                        }dj                  t        j                               }g }|D ]  }	|	t        j                  k(  rt        j                  nt        j                  }
|j                  t        j                  j                  t        j                  t        j                   t        j"                  |	j$                  |
||              d}|rd}|}|rd| d}n{d}| t&        j(                  k(  r6|st        d	t&        j(                         t        j+                  ||      }d
}|j-                  dd      }|}|r|j-                  dd      }|}d| d}t        j.                  j1                  | j3                         |       } t        j4                  j                  t        j6                  t        j8                  | j3                         |||dj                  |            }d| dS )zM
        Builds fully executable DGQL query either by id or by name.
        z0Either object_name or object_id must be providedz, )edge_key
source_key
target_key	directiondir
edge_typesr=    rE   z, parentId:""r<   zVersion cant be empty for Nz\\"z, parentName:")nodeKey	domainKeyr9   
object_keyquery_objectparent_paramedgeszselect SYSTEM$DGQL('z'))r&   joinr8   r[   r3   r!   r   r-   r]   rc   rd   appendry   EDGE_TEMPLETEformatrg   rh   ri   r   rk   rl   _get_feature_view_namereplaceUSER_TO_SYSTEM_DOMAIN_MAPgetupperQUERY_TEMPLETErf   rJ   )rz   r{   r|   r}   r~   r   properties_stringedge_types_formattedpartsr   dir_keyr   r   r   querys                  r    build_queryz_DGQLQueryBuilder.build_query   s    +yOPP IIl&J&JK#yy)9)9);<( 	I  0 ; ;;  ^^ 
 LL!//66(--*11*11'oo30 7 
	& J$L!-i[:J 8 88%$4[5M5M4NO  0FF "&%--c7;K&L!/!7!7W!E-!/}A>)CCGG!=
 "0077$$")) &&(!%%''%. 8 
 &eWB//r)   c                 2    t        j                  d|       }|S )z
        Splits the fully qualified name.
        Pattern matches either a string enclosed in double quotes or a sequence of word characters.
        z"[^"]*"|\w+)refindall)r<   r   s     r    split_fully_qualified_namez,_DGQLQueryBuilder.split_fully_qualified_name   s     

>40r)   r<   rD   c                 2   t         j                  |       }t        |      dk7  rt        d      |d   }|j	                  d      r#|j                  d      r|j                  d      }n|j                         }d| d| d}dj                  |dd |gz         S )z/
        Constructs feature view name.
           z*Invalid object name: less than three partsr   r   $.N)	ry   r   lenr&   
startswithendswithstripr   r   )r<   rD   r   	name_partfeature_view_names        r    r   z(_DGQLQueryBuilder._get_feature_view_name   s    
 "<<TBu:?IJJ!H	 $););C)@!,I!)I  	{!G9A6xxbq	%6$7788r)   )NNNN)r'   r*   r+   r,   r   r   rk   rl   rp   rq   rm   rr   rn   rw   r   staticmethodstrr   r   r   r   r   r   r1   r)   r    ry   ry      s    cMtN  "2"8"8+22-BB!  &*#'(,#'J0J0./J0 c]J0 C=	J0
 !J0 C=J0 
J0 J0X   9S 93 93 9 9r)   ry   c                      e Zd ZdZddZ	 ddededeee	e	e
ef      fdZ	 d ded	eded
edee   deee	e	e
ef      fdZdeee	e	e
ef      dededeee	e	e
ef      deddfdZdeeef   defdZdeeef   fdZdeeef   defdZdeee	e	e
ef      ddfdZded	eddfdZdej2                  edded	edee   deeef   deddfdZy)!Lineagez
    Provides methods for exploring lineage of Snowflake objects.
    To access an object of this class, use :attr:`Session.lineage`.
    r   Nc                     || _         t        j                  t        j                  t        j
                  t        j                  h| _        y r   )_sessionrk   rl   rm   rp   rs   rt   _versioned_object_domains)selfsessions     r    __init__zLineage.__init__  s7    $$$$''	*
&r)   query_stringr   c                 
   | j                   j                  |      }t        j                  |j	                         d   d         }g }|j                  t        j                  i       j                  t        j                  i       j                  |j                  g       }|D ]_  }t        j                  |v st        j                  |v s)|j                  |t        j                     |t        j                     ||f       a |S )zk
        Constructs and executes a query to trace the lineage of a given entity at a distance one.
        r   )r   sqljsonloadscollectr   r]   re   rf   r   rh   ri   r   )	r   r   r   current_distanceresponsejson_responserowsr   edges	            r    _get_lineagezLineage._get_lineage  s     ==$$\2

8#3#3#5a#8#;<k..3S!!2&S"% 	  		D!!T)k.@.@D.H[//0[//0!(			 r)   r|   rz   total_distancer~   c                    t               }g }t               }| j                  t        j	                  ||g||      |d      }	| j                  |	|||d       |r|j                         \  }}
}}||k(  r||
||f}||v r(|j                  |       | j                  t        j	                  ||g|
|      ||dz         }	| j                  |	||||dz          |r|S )ze
        Traces lineage by making successive DGQL queries based on response nodes using BFS.
        )r|   r~   r   )r   )r}   r   )setr   r   ry   r   _process_lineage_edgespopleftadd)r   r|   rz   r   r   r~   visitedresultsqueuelineage_edgesr}   r   r   current_nodes                 r    _tracezLineage._trace8  s0    %))))'-	 *   * 	
 	##M9eWaP    >1  	L w&KK% --!--!I;)y .   1$M ''y%:JQ:N= D r)   r   r   r   r   c                    |sy|j                  |       |D ]  }|t        j                  k(  r|d   n|d   }d}t        j                  |v r^|t        j                     }	t        j
                  |	v r|	t        j
                     }n%t        j                  |	v r|	t        j                     }|j                  |t        j                     |t        j                     ||f        y)zI
        Process lineage edges and update the queue accordingly.
        Nr   r   )
extendr   r-   r8   rN   rW   rX   r   rJ   rV   )
r   r   r   r   r   r   r   next_objectr   r=   s
             r    r   zLineage._process_lineage_edgesx  s     }%! 	D$(8(C(CCQa  I&&+5()@)@A
))Z7 *<+A+A BI!66*D *<+L+L MILL 3 340$		r)   entityc                 ,    |t         j                     dv S )zJ
        Determines if the entity should not be explored further.
        >   MASKEDDELETED)r8   rQ   )r   r   s     r    _is_terminal_entityzLineage._is_terminal_entity  s     l))*.CCCr)   graph_entityc                    |t         j                     }|t         j                     }|t         j                     }|t         j                     }|| j
                  v r|t        j                  k(  rd|v r|j                  d      xr |j                  d      }|j                  d      j                  d      }t        |      dk\  r6dj                  |dd       }|d   }	|rd| d}| d| d| |	fS t        j                  dt        j                   d      t         j                   |v r|t         j                      }
t         j"                  |
v r|
t         j"                     }nat         j$                  |t         j                      v r|
t         j$                     }n*t        j                  d	|t         j                      d      | d| d| |fS t        j                  d	|t         j                      d      |t&        j(                  k(  rht         j                   |v rVt         j"                  |t         j                      v r3|t         j                      }
| d| d|
t         j"                      d| dfS | d| d| dfS )
zX
        Extracts and returns the name and version from the given graph entity.
        r   r   r   Nr   zunexpected z name format.z&missing name/version field for domain )r8   rL   rP   rO   rM   r   rk   rl   r   r   r   splitr   r   r   SERVER_FAILED_FETCH_LINEAGErN   rS   rT   rp   rv   )r   r   user_domainr?   r>   r<   
had_quotesr   	base_namerD   r=   parent_names               r    _get_name_and_versionzLineage._get_name_and_version  s    #<#;#;<,//*l112L--.$888k666$;!%!5!L$--:LJ JJsO11#6E5zQ$'HHU3BZ$8	"')%*+I;a(8I#%$axq <gFF9UU%k&>&>%?}M  ((L8),*A*AB
++z9",\-E-E"FK 77#L$;$;<= #-\-P-P"QK9UU@lNfNfAg@hhij  $axq6==5QQ<\,JbJb=c<ddef 
 +222''<7((L9P9P,QQ%l&=&=>J$axqL,D,D!E FavN 
 $axq'..r)   c           	      2   | j                  |      \  }}|j                  t        j                        xs@ |j                  t        j                        xs |j                  t        j
                        }|j                  t        j                        t        j                  k(  r@|j                  t        j                        t        j                  k(  rt        j                  }t        j                  |vr't        j                  dt        j                   d      t        j                  |vr't        j                  dt        j                   d      t        |t        j                           dz  }t        j                  j                  |t        j                   j"                        }|j%                  d      }t        j&                  |t        j
                  |t        j                  |t        j                  |t        j                     i}|r||t        j(                  <   |t        j*                  k(  r[t        j,                  |v rI|t        j,                     }	t        j.                  |	v r$|	t        j.                     |t        j0                  <   |S )zO
        Transforms the given graph entity into a user visible entity.
        zmissing z
 property.i  )tzz%Y-%m-%dT%H:%M:%SZ)r   r   r8   rL   rK   rJ   rp   rq   ru   rR   r   r   rQ   intdatetimefromtimestamptimezoneutcstrftimerM   rU   rv   rN   rY   rZ   )
r   r   r<   rD   r9   	timestampdt_utcformatted_date_isouser_entityr=   s
             r    _get_user_entityzLineage._get_user_entity  s    22<@g \556 5 ; ;<5 3 34 	 \556:J:P:PP  !<!<=AQAVAVV%**F"",61MM<223:>  l21MM<../z:  \%<%<=>E	""00x?P?P?T?T0U#__-ABt##%7l.A.A!B	
 07K,,-%,,,&&,6),*A*AB
**j85?@W@W5XK 1 12r)   lineage_tracez&snowflake.snowpark.dataframe.DataFramec           
         g }|D ]Y  }|j                  | j                  |d         | j                  |d         |d   j                  j                         |d   f       [ t	        t        dt                     t        dt                     t        dt                     t        dt                     g      }| j                  j                  ||	      S )
z<
        Constructs a dataframe of lineage results.
        r   r   r   r   source_objecttarget_objectr   distance)r>   )r   r   r   
capitalizer   r   r   r   r   r   create_dataframe)r   r   transformed_resultsr   r>   s        r    _get_result_dataframezLineage._get_result_dataframe  s     !! 	D&&))$q'2))$q'2GMM,,.G		 O[];O[];K6J6	
 }}--.A&-QQr)   c                 "   t         j                  |      }|j                         t        j                  k(  }|rt        |      dk7  s|st        |      dk7  rt        d|       |D ]&  }t        j                  d|      rt        d|        y)a  
        Checks if the object name is one of the below allowed format
            Non-Case-sensitive: "database.schema.object" or "database.schema.object.column_name"
            Case-sensitive: ""database"."schema"."object"" or ""database"."schema"."object""."column_name"
           r   zInvalid object name: z^"[^"]*"$|\w+N)	ry   r   r   rp   rv   r   r&   r   match)r   r|   rz   r   is_column_domainparts         r    _check_valid_object_namez Lineage._check_valid_object_name)  s     "<<[I(..04D4K4KKUq SZ1_4[MBCC 	HD 88,d3 #8!FGG		Hr)   )r~   r   r   r   c          
         |t         k  s	|t        kD  rt        dt          dt         d      | j                  ||       t	        |t
              rt        j                  |      }|t        j                  k(  r t        j                  t        j                  gn|g}g }|D ]&  }|j                  | j                  |||||             ( | j                  |      S )a  
        Traces the lineage of an object within Snowflake and returns it as a DataFrame.

        Args:
            object_name (str): The fully qualified name of the Snowflake object to start trace, formatted as below:
                    Non-Case-sensitive: "database.schema.object"
                    Case-sensitive: ""database"."schema"."object""
            object_domain (str): The domain of the Snowflake object to start trace. e.g., "table", "view".
            object_version (Optional[str]):Version of the versioned Snowflake object (e.g., model or dataset) to begin tracing. Defaults to None.
            direction (LineageDirection): The direction to trace (UPSTREAM, DOWNSTREAM, BOTH), defaults to BOTH.
            distance (int): Trace distance, defaults to 2, with a maximum of 5.

        Returns:
            snowflake.snowpark.DataFrame: A DataFrame representing the traced lineage with the following schema:
                - source (str): The source of the lineage.
                - target (str): The target of the lineage.
                - direction (str): The direction of the lineage ('upstream', 'downstream', or 'both').
                - distance (int): The distance of the lineage tracing from given object.

            Example:
                >>> db = session.get_current_database().replace('"', "")
                >>> schema = session.get_current_schema().replace('"', "")
                >>> _ = session.sql(f"CREATE OR REPLACE TABLE {db}.{schema}.T1(C1 INT)").collect()
                >>> _ = session.sql(
                ...     f"CREATE OR REPLACE VIEW {db}.{schema}.V1 AS SELECT * FROM {db}.{schema}.T1"
                ... ).collect()
                >>> _ = session.sql(
                ...     f"CREATE OR REPLACE VIEW {db}.{schema}.V2 AS SELECT * FROM {db}.{schema}.V1"
                ... ).collect()
                >>> df = session.lineage.trace(
                ...     f"{db}.{schema}.T1",
                ...     "table",
                ...     direction="downstream"
                ... )
                >>> df.show() # doctest: +SKIP
                -------------------------------------------------------------------------------------------------------------------------------------------------
                | "SOURCE_OBJECT"                                         | "TARGET_OBJECT"                                        | "DIRECTION"   | "DISTANCE" |
                -------------------------------------------------------------------------------------------------------------------------------------------------
                | {"createdOn": "2023-11-15T12:30:23Z", "domain": "TABLE",| {"createdOn": "2023-11-15T12:30:23Z", "domain": "VIEW",| "Downstream"  | 1          |
                |  "name": "YOUR_DATABASE.YOUR_SCHEMA.T1", "status":      |  "name": "YOUR_DATABASE.YOUR_SCHEMA.V1", "status":     |               |            |
                |  "ACTIVE"}                                              |  "ACTIVE"}                                             |               |            |
                | {"createdOn": "2023-11-15T12:30:23Z", "domain": "VIEW", | {"createdOn": "2023-11-15T12:30:23Z", "domain": "VIEW",| "Downstream"  | 2          |
                |  "name": "YOUR_DATABASE.YOUR_SCHEMA.V1", "status":      |  "name": "YOUR_DATABASE.YOUR_SCHEMA.V2", "status":     |               |            |
                |  "ACTIVE"}                                              |  "ACTIVE"}                                             |               |            |
                -------------------------------------------------------------------------------------------------------------------------------------------------
                <BLANKLINE>
        zDistance must be between z and r   )_MIN_TRACE_DISTANCE_MAX_TRACE_DISTANCEr&   r   
isinstancer   r   r(   r/   r.   r-   r   r   r   )	r   r|   rz   r~   r   r   
directionsr   r   s	            r    tracezLineage.trace=  s    p ))X8K-K+,?+@FYEZZ[\  	%%k=Ai%(11)<I ,111 &&(8(C(CD 	
  	C  KX~V	
 ))-88r)   )r   z"snowflake.snowpark.session.Sessionr   N)r   r   )r'   r*   r+   r,   r   r   r   r   r	   r   r   r   r   r   r   r   r   r   r   boolr   r   r   r   r   r/   _DEFAULT_TRACE_DISTANCEr
   r  r1   r)   r    r   r   
  s   

 	 $
 
eKj#=>	?J )->> > $	>
 > !> 
eKj#=>	?>@"E+{J"KLM" $" 	"
 eKj#EFG" " 
"HD$sCx. DT D6/$sCx. 6/p1T#s(^ 1 1fR!%[*c(Q"RSR	1R8HC H HPT H2 )-2B2G2G/M9M9 M9
 !M9 ../M9 M9 
2M9r)   r   )#r   r   r   collectionsr   enumr   typingr   r   r   r   r	   r
   snowflake.snowpark	snowflake*snowflake.snowpark._internal.error_messager   snowflake.snowpark.typesr   r   r   r   r   r   r   r  r   r3   r8   r]   rk   rp   ry   r   r1   r)   r    <module>r     s   
   	   : :  V     Ot O6
0 
0# #L  2 2w9 w9t@9 @9r)   