a
    bgF                     @   sT  d dl Z d dlmZ d dlmZmZmZmZ d dlm	Z	 d dl
mZmZmZ d dlmZ e 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eeef eeef dddZ eeeef  eeeef  eeef dddZ!eeef edddZ"eedddZ#e$e e%ee& dd d!Z'e$e e%ee& d"d#d$Z(G d%d& d&eZ)dS )'    N)md5)AnyDictListOptional)get_from_dict_or_env)GraphDocumentNodeRelationship)
GraphStoreZ
__Entity__z
SHOW SCHEMA INFO
z
CALL schema.node_type_properties()
YIELD nodeType AS label, propertyName AS property, propertyTypes AS type
WITH label AS nodeLabels, collect({key: property, types: type}) AS properties
RETURN {labels: nodeLabels, properties: properties} AS output
a?  
MATCH (n)-[e]->(m)
WITH DISTINCT
    labels(n) AS start_node_labels,
    type(e) AS rel_type,
    labels(m) AS end_node_labels,
    e,
    keys(e) AS properties
UNWIND CASE WHEN size(properties) > 0 THEN properties ELSE [null] END AS prop
WITH
    start_node_labels,
    rel_type,
    end_node_labels,
    CASE WHEN prop IS NULL THEN [] ELSE [prop, valueType(e[prop])] END AS property_info
RETURN
    start_node_labels,
    rel_type,
    end_node_labels,
    COLLECT(DISTINCT CASE 
    WHEN property_info <> [] 
    THEN property_info 
    ELSE null END) AS properties_info
zv
UNWIND $data AS row
CALL merge.node(row.label, row.properties, {}, {}) 
YIELD node 
RETURN distinct 'done' AS result
z|
UNWIND $data AS row
MERGE (source {id: row.source_id})
MERGE (target {id: row.target_id})
RETURN distinct 'done' AS result
z
UNWIND $data AS row
MATCH (source {id: row.source_id})
MATCH (target {id: row.target_id})
WITH source, target, row
CALL merge.relationship(source, row.type, {}, {}, target, {})
YIELD rel
RETURN distinct 'done' AS result
z
MERGE (d:Document {id:$document.metadata.id})
SET d.content = $document.page_content
SET d += $document.metadata
RETURN distinct 'done' AS result
z
UNWIND $data AS row
MATCH (source {id: row.source_id}), (d:Document {id: $document.metadata.id})
MERGE (d)-[:MENTIONS]->(source)
RETURN distinct 'done' AS result
z1
Node labels and properties (name and type) are:
z)
Relationship labels and properties are:
z7
Nodes are connected with the following relationships:
)datareturnc                 C   s&   dd | d D dd | d D dS )Nc                 S   s4   g | ],}|d  dd |d D |d |d dqS )end_node_labelsc                 S   s(   g | ] }|d  dd |d D dqS )keyc                 S   s   g | ]}d |d    iqS typelower.0Z	type_item r   w/var/www/html/cobodadashboardai.evdpl.com/venv/lib/python3.9/site-packages/langchain_community/graphs/memgraph_graph.py
<listcomp>m   s   ;get_schema_subset.<locals>.<listcomp>.<listcomp>.<listcomp>typesr   r   r   r   propr   r   r   r   j   s   0get_schema_subset.<locals>.<listcomp>.<listcomp>
propertiesstart_node_labelsr   r   r   r    r   r   )r   edger   r   r   r   g   s   
z%get_schema_subset.<locals>.<listcomp>edgesc                 S   s(   g | ] }|d  dd |d D dqS )labelsc                 S   s(   g | ] }|d  dd |d D dqS )r   c                 S   s   g | ]}d |d    iqS r   r   r   r   r   r   r      s   r   r   r   r   r   r   r   r   r   |   s   r   r   r$   r   r   )r   noder   r   r   r   y   s   nodesr#   r'   r   r   r   r   r   get_schema_subsete   s    r*   )r'   relsr   c                 C   s   dd |D dd | D dS )Nc                 S   s4   g | ],}|d  dd |d D |d |d dqS )r   c                 S   s(   g | ] }|d  d|d   igdqS )r   r      r   r   r   r   r   r   r      s   4get_reformated_schema.<locals>.<listcomp>.<listcomp>Zproperties_infor    rel_typer!   r   )r   relr   r   r   r      s   
z)get_reformated_schema.<locals>.<listcomp>c                    s:   g | ]2 t  d  dd g fdd d D dqS )r$   r,   Nc                    s<   g | ]4} d  d d dkr|d dd |d D dqS )r   r   r    c                 S   s   g | ]}d |  iqS r   r   r   r   r   r   r      s   z?get_reformated_schema.<locals>.<listcomp>.<listcomp>.<listcomp>r   r   r   r   r&   r   r   r      s   r-   r   r%   )_remove_backticks)r   r   r1   r   r      s   
r(   r   )r'   r+   r   r   r   get_reformated_schema   s    
r3   )schemar   c              	   C   sp  d}d}d}| d D ]t}|dd |d  d7 }|d g kr@q|d7 }|d D ]6}d	 d
d |d D }|d|d  d| d7 }qPq| d D ]}|d }d |d }	d |d }
|d|	 d| d|
 d7 }|d g krq|d| d7 }|d D ]6}d	 dd |d D }|d|d  d| d7 }qqd |rHt| nd|rXt| nd|rht| ndgS )Nr0   r'   z- labels: (::r$   z)
r   z  properties:
z or c                 S   s   h | ]}|d  qS r   r   r   Z
prop_typesr   r   r   	<setcomp>       z+transform_schema_to_text.<locals>.<setcomp>r   z    - r   z: 
r#   r   r    r   z(:z)-[:z]->(:z
- labels: z
  properties:
c                 S   s   h | ]}|d    qS r   r   r6   r   r   r   r7      r8   )joinNODE_PROPS_TEXTREL_PROPS_TEXTREL_TEXT)r4   Znode_props_dataZrel_props_datarel_datar&   r   Zprop_types_strr/   r.   Zstart_labelsZ
end_labelsr   r   r   transform_schema_to_text   s@    r?   )textr   c                 C   s   |  ddS )N`r0   )replace)r@   r   r   r   r2      s    r2   )r'   baseEntityLabelr   c                 C   sT   g }| D ]F}|j d|jiB }|r.t|jtgn
t|jg}||d}|| q|S )Nid)labelr   )r   rD   r2   r   BASE_ENTITY_LABELappend)r'   rC   Ztransformed_nodesr&   Zproperties_dictrE   Z	node_dictr   r   r   _transform_nodes   s    

rH   )relationshipsrC   r   c                 C   sb   g }| D ]T}t |j|rtgnt |jjg|jj|r:tgnt |jjg|jjd}|| q|S )N)r   Zsource_labelZ	source_idZtarget_labelZ	target_id)r2   r   rF   sourcerD   targetrG   )rI   rC   Ztransformed_relationshipsr/   Zrel_dictr   r   r   _transform_relationships   s    rL   c                
   @   s   e Zd ZdZdddee ee ee ee eee ddddZddd	d
Z	e
edddZe
eeef dddZi feeeeeef  dddZddddZdee eeddddZdS )MemgraphGrapha  Memgraph wrapper for graph operations.

    Parameters:
    url (Optional[str]): The URL of the Memgraph database server.
    username (Optional[str]): The username for database authentication.
    password (Optional[str]): The password for database authentication.
    database (str): The name of the database to connect to. Default is 'memgraph'.
    refresh_schema (bool): A flag whether to refresh schema information
    at initialization. Default is True.
    driver_config (Dict): Configuration passed to Neo4j Driver.

    *Security note*: Make sure that the database connection uses credentials
        that are narrowly-scoped to only include necessary permissions.
        Failure to do so may result in data corruption or loss, since the calling
        code may attempt commands that would result in deletion, mutation
        of data if appropriately prompted or reading sensitive data if such
        data is present in the database.
        The best way to guard against such negative outcomes is to (as appropriate)
        limit the permissions granted to the credentials used with this tool.

        See https://python.langchain.com/docs/security for more information.
    NT)driver_config)urlusernamepassworddatabaserefresh_schemarN   r   c          
   
   C   sJ  zddl }W n ty&   tdY n0 td|idd}|dkrN|dkrNd}n(td|idd}td	|id	d
}||f}td|iddd}|jj|fd|i|pi | _|| _d| _i | _z| j	  W n< |j
jy   tdY n  |j
jy   tdY n0 |rFz|   W n. |j
jyD }	 z|	W Y d}	~	n
d}	~	0 0 dS )z-Create a new Memgraph graph wrapper instance.r   NzRCould not import neo4j python package. Please install it with `pip install neo4j`.rO   ZMEMGRAPH_URIr0   rP   ZMEMGRAPH_USERNAMErQ   ZMEMGRAPH_PASSWORDrR   ZMEMGRAPH_DATABASEZmemgraphauthzMCould not connect to Memgraph database. Please ensure that the url is correctz`Could not connect to Memgraph database. Please ensure that the username and password are correct)neo4jImportErrorr   ZGraphDatabaseZdriver_driver	_databaser4   structured_schemaZverify_connectivity
exceptionsZServiceUnavailable
ValueErrorZ	AuthErrorrS   ZClientError)
selfrO   rP   rQ   rR   rS   rN   rU   rT   er   r   r   __init__  s`    

zMemgraphGraph.__init__)r   c                 C   s$   | j r td | j   d | _ d S )NzClosing the driver connection.)rW   loggerinfocloser\   r   r   r   ra   _  s    

zMemgraphGraph.closec                 C   s   | j S )z(Returns the schema of the Graph database)r4   rb   r   r   r   
get_schemae  s    zMemgraphGraph.get_schemac                 C   s   | j S )z3Returns the structured schema of the Graph database)rY   rb   r   r   r   get_structured_schemaj  s    z#MemgraphGraph.get_structured_schema)queryparamsr   c           	   
   C   s  ddl m} z.| jj|| j|d\}}}dd |D }|W S  |y } zr|jdks^|jdkrhd|jv s|jd	krd
|jv sd|jv s|jdkrd|jv s|jdkrd|jv s W Y d}~n
d}~0 0 | jj| jd.}|||}dd |D }|W  d   S 1 s0    Y  dS )a	  Query the graph.

        Args:
            query (str): The Cypher query to execute.
            params (dict): The parameters to pass to the query.

        Returns:
            List[Dict[str, Any]]: The list of dictionaries containing the query results.
        r   
Neo4jError)Z	database_Zparameters_c                 S   s   g | ]}|  qS r   r)   r   rr   r   r   r     r8   z'MemgraphGraph.query.<locals>.<listcomp>z+Neo.DatabaseError.Statement.ExecutionFailedz4Neo.DatabaseError.Transaction.TransactionStartFailedzin an implicit transactionz'Neo.ClientError.Statement.SemanticErrorz&in an open transaction is not possiblez+tried to execute in an explicit transaction0Memgraph.ClientError.MemgraphError.MemgraphErrorzin multicommand transactionsSchemaInfo disabledN)rR   c                 S   s   g | ]}|  qS r   r)   ri   r   r   r   r     r8   )	neo4j.exceptionsrh   rW   Zexecute_queryrX   codemessagesessionrun)	r\   re   rf   rh   r   _Z	json_datar]   rp   r   r   r   re   o  sJ    

zMemgraphGraph.queryc           	   
   C   s  ddl }ddlm} | dg kr&dS zf| td d}|dur`t|t|jfr`|	|}n|}|duspJ t
|}|| _t|| _W dS  |y } z*|jdkrd|jv rtd W Y d}~n
d}~0 0 d	d
 | tD }| t}t||}|| _t|| _dS )zB
        Refreshes the Memgraph graph schema information.
        r   Nrg   zMATCH (n) RETURN n LIMIT 1r4   rk   rl   zSchema generation with SHOW SCHEMA INFO query failed. Set --schema-info-enabled=true to use SHOW SCHEMA INFO query. Falling back to alternative queries.c                 S   s   g | ]}|d  qS )outputr   )r   re   r   r   r   r     r8   z0MemgraphGraph.refresh_schema.<locals>.<listcomp>)astrm   rh   re   SCHEMA_QUERYget
isinstancestrASTliteral_evalr*   rY   r?   r4   rn   ro   r_   r`   NODE_PROPERTIES_QUERY	REL_QUERYr3   )	r\   rt   rh   resultZschema_resultrY   r]   r'   r+   r   r   r   rS     s6    


zMemgraphGraph.refresh_schemaF)graph_documentsinclude_sourcerC   r   c                 C   s   |r:|  dt d |  dt d |  dt d |D ]}|r|jjdsrt|jjd |jjd< |  t	d|jj
i |  td	t|j|i t|j|}|  td	|i |  td	|i |r>|  t||jj
d
 q>|   dS )a*  
        Take GraphDocument as input as uses it to construct a graph in Memgraph.

        Parameters:
        - graph_documents (List[GraphDocument]): A list of GraphDocument objects
        that contain the nodes and relationships to be added to the graph. Each
        GraphDocument should encapsulate the structure of part of the graph,
        including nodes, relationships, and the source document information.
        - include_source (bool, optional): If True, stores the source document
        and links it to nodes in the graph using the MENTIONS relationship.
        This is useful for tracing back the origin of data. Merges source
        documents based on the `id` property from the source document metadata
        if available; otherwise it calculates the MD5 hash of `page_content`
        for merging process. Defaults to False.
        - baseEntityLabel (bool, optional): If True, each newly created node
        gets a secondary __Entity__ label, which is indexed and improves import
        speed and performance. Defaults to False.
        zCREATE CONSTRAINT ON (b:z) ASSERT b.id IS UNIQUE;zCREATE INDEX ON :z(id);;rD   zutf-8documentr   )r   r   N)re   rF   rJ   metadatarv   r   Zpage_contentencode	hexdigestINCLUDE_DOCS_QUERY__dict__NODE_IMPORT_QUERYrH   r'   rL   rI   REL_NODES_IMPORT_QUERYREL_IMPORT_QUERYINCLUDE_DOCS_SOURCE_QUERYrS   )r\   r~   r   rC   r   r>   r   r   r   add_graph_documents  s@    
z!MemgraphGraph.add_graph_documents)NNNNT)FF)__name__
__module____qualname____doc__r   rx   boolr   r^   ra   propertyrc   r   rd   dictr   re   rS   r   r   r   r   r   r   rM     s@        E"6.  rM   )*logginghashlibr   typingr   r   r   r   Zlangchain_core.utilsr   Z)langchain_community.graphs.graph_documentr   r	   r
   Z&langchain_community.graphs.graph_storer   	getLoggerr   r_   rF   ru   r{   r|   r   r   r   r   r   r;   r<   r=   rx   r*   r3   r?   r2   listr   r   rH   rL   rM   r   r   r   r   <module>   s:   

 (
#)