o
    NDiY                     @   sr  d dl mZ d dlZ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 d dl
mZmZ d dlmZmZmZ d dlmZ d d	lmZ d d
lmZ dZedddgZeeZeddZdd Zd8ddZd8ddZ d9ddZ!d9ddZ"dd Z#d:ddZ$d9d d!Z%d"d# Z&d9d$d%Z'd:d&d'Z(d(d) Z)d*d+ Z*d9d,d-Z+d.d/ Z,d9d0d1Z-d:d2d3Z.d9d4d5Z/d6d7 Z0dS );    )
namedtupleN)product)metadata)CQLEngineException)columnsquery)executeget_clusterformat_log_context)Model)
NamedTable)UserTypeCQLENG_ALLOW_SCHEMA_MANAGEMENTFieldnametypesystemschema_columnfamiliesc                 C   sZ   | rt | ttfstd|rt |ttfstd| r| ndg} |r%|ndg}t|| S )z!Return all the execution contextsz$keyspaces must be a list or a tuple.z&connections must be a list or a tuple.N)
isinstancelisttuple
ValueErrorr   )	keyspacesconnections r   W/var/www/Datamplify/venv/lib/python3.10/site-packages/cassandra/cqlengine/management.py_get_context(   s   
r   Tc                 C   s   t | |dd|i|d dS )a  
    Creates a keyspace with SimpleStrategy for replica placement

    If the keyspace already exists, it will not be modified.

    **This function should be used with caution, especially in production environments.
    Take care to execute schema modifications in a single context (i.e. not concurrently with other clients).**

    *There are plans to guard schema-modifying functions with an environment-driven conditional.*

    :param str name: name of keyspace to create
    :param int replication_factor: keyspace replication factor, used with :attr:`~.SimpleStrategy`
    :param bool durable_writes: Write log is bypassed if set to False
    :param list connections: List of connection names
    SimpleStrategyreplication_factorr   N_create_keyspace)r   r   durable_writesr   r   r   r   create_keyspace_simple9   s   
r#   c                 C   s   t | |d||d dS )a  
    Creates a keyspace with NetworkTopologyStrategy for replica placement

    If the keyspace already exists, it will not be modified.

    **This function should be used with caution, especially in production environments.
    Take care to execute schema modifications in a single context (i.e. not concurrently with other clients).**

    *There are plans to guard schema-modifying functions with an environment-driven conditional.*

    :param str name: name of keyspace to create
    :param dict dc_replication_map: map of dc_names: replication_factor
    :param bool durable_writes: Write log is bypassed if set to False
    :param list connections: List of connection names
    NetworkTopologyStrategyr   Nr    )r   dc_replication_mapr"   r   r   r   r    create_keyspace_network_topologyM   s   r&   c                 C   sd   t  sd S |rt|ttfstdddd}|r)|D ]}|| ||||d qd S || ||| d S )N&Connections must be a list or a tuple.c                 S   sd   t |}| |jjvr&ttd|d|  t| |||}t| |d d S ttd|d|  d S )NzCreating keyspace %s
connectionz2Not creating keyspace %s because it already exists)	r	   r   r   loginfor
   KeyspaceMetadatar   as_cql_query)r   r"   strategy_classstrategy_optionsr)   clusterks_metar   r   r   __create_keyspaceh   s   z+_create_keyspace.<locals>.__create_keyspacer(   N_allow_schema_modificationr   r   r   r   )r   r"   r.   r/   r   r2   r)   r   r   r   r!   `   s   

r!   c                 C   sV   t  sdS |rt|ttfstdddd}|r%|D ]}|| | qdS ||  dS )a  
    Drops a keyspace, if it exists.

    *There are plans to guard schema-modifying functions with an environment-driven conditional.*

    **This function should be used with caution, especially in production environments.
    Take care to execute schema modifications in a single context (i.e. not concurrently with other clients).**

    :param str name: name of keyspace to drop
    :param list connections: List of connection names
    Nr'   c                 S   s4   t |}| |jjv rtdt| |d d S d S )NzDROP KEYSPACE {0}r(   )r	   r   r   r   formatprotect_name)r   r)   r0   r   r   r   _drop_keyspace   s   z%drop_keyspace.<locals>._drop_keyspacer3   r4   )r   r   r8   r)   r   r   r   drop_keyspacey   s   
r9   c                 C   sL   t |}|d| g}| j D ]}t|j}|d|v r#|j  S qdS )z;
    Find the index name for a given table and column.
    z
values(%s)targetN)r   r7   indexesvaluesdictindex_optionsgetr   )tablecolumn_nameprotected_namepossible_index_valuesindex_metadataoptionsr   r   r   _get_index_name_by_column   s   


rF   c              	   C   V   t ||}|D ]!\}}tj| |d}t||d W d   n1 s#w   Y  qdS )a5  
    Inspects the model and creates / updates the corresponding table and columns.

    If `keyspaces` is specified, the table will be synched for all specified keyspaces.
    Note that the `Model.__keyspace__` is ignored in that case.

    If `connections` is specified, the table will be synched for all specified connections. Note that the `Model.__connection__` is ignored in that case.
    If not specified, it will try to get the connection from the Model.

    Any User Defined Types used in the table are implicitly synchronized.

    This function can only add fields that are not part of the primary key.

    Note that the attributes removed from the model are not deleted on the database.
    They become effectively ignored by (will not show up on) the model.

    **This function should be used with caution, especially in production environments.
    Take care to execute schema modifications in a single context (i.e. not concurrently with other clients).**

    *There are plans to guard schema-modifying functions with an environment-driven conditional.*
    keyspacer(   N)r   r   ContextQuery_sync_tablemodelr   r   contextr)   rI   mr   r   r   
sync_table   s   
rP   c              
      s  t  sd S t| tstd| jrtd|  }|  }|  }|p&|  }t	|}z|j
j| }W n tyH   td|d}t||| w |j}t  | j D ]}	g }
t|	|
  fdd|
D D ]
}t|| |d qgqT||vrttd||d| t| }zt||d W n ty } zd	t|vr W Y d }~nd }~ww ttd
||d| || }t| | |j}t }| j D ]\\}}	|	j}|| ||v r|| }|j|	j krtd||d}||||j|	j }t!"| t#| q|	j$s|	j$rtd||d}t||||d||	% }t||d q|&|}|r<td||d}t'||| t(| |d |j
j| j| }dd | j D }|D ]-}t)||j}|rdqWdg}|d|g7 }|d|jg7 }d*|}t||d qWd S )Nz'Models must be derived from base Model.z'cannot create table from abstract modelz,Keyspace '{0}' for model {1} does not exist.r(   c                       g | ]}| vr|qS r   r   .0usyncd_typesr   r   
<listcomp>       z_sync_table.<locals>.<listcomp>z sync_table creating new table %srI   r)   z)Cannot add already existing column familyz%sync_table checking existing table %szsExisting table {0} has column "{1}" with a type ({2}) differing from the model type ({3}). Model should be updated.zHCannot add primary key '{0}' (with db_field '{1}') to existing table {2}zALTER TABLE {0} add {1}z1Table {0} has fields not referenced by model: {1}c                 S   s   g | ]	\}}|j r|qS r   )index)rS   ncr   r   r   rW     s    zCREATE INDEXzON {0}z("{0}") )+r5   
issubclassr   r   __abstract__column_family_name_raw_column_family_name_get_keyspace_get_connectionr	   r   r   KeyErrorr
   r6   tablesset_columnsr<   r   resolve_udts
_sync_typer*   debug_get_create_tabler   str_validate_pkitemsdb_field_nameaddcql_typedb_typewarningswarnwarningprimary_keyget_column_defsymmetric_differencer+   _update_optionsrF   join)rM   r)   cf_nameraw_cf_nameks_namer0   rI   msgre   coludtsudtqsex
table_metatable_columnsmodel_fields
model_namedb_namecol_metar   db_fields_not_in_modelr@   r;   column
index_namer   rU   r   rK      s   






rK   c              	   C   s   dd | j  D }dd |jD }dd | j D }dd |jD }||ks,||krBdd }td| |  ||||||d S )	Nc                 S      g | ]}|j qS r   ro   rS   r\   r   r   r   rW   #      z _validate_pk.<locals>.<listcomp>c                 S   r   r   r   r   r   r   r   rW   $  r   c                 S   r   r   r   r   r   r   r   rW   %  r   c                 S   r   r   r   r   r   r   r   rW   &  r   c                 S   s&   d d| |rdd| S dS )NPRIMARY KEY (({0}){1}),  )r6   rz   )	partition
clusteringr   r   r   
_pk_string)  s   &z _validate_pk.<locals>._pk_stringz|Model {0} PRIMARY KEY composition does not match existing table {1}. Model: {2}; Table: {3}. Update model or drop the table.)_partition_keysr<   partition_key_clustering_keysclustering_keyr   r6   r`   )rM   r   model_partitionmeta_partitionmodel_clusteringmeta_clusteringr   r   r   r   rm   "  s   
rm   c                 C   s.   t  sdS t|tstdt| ||d dS )aE  
    Inspects the type_model and creates / updates the corresponding type.

    Note that the attributes removed from the type_model are not deleted on the database (this operation is not supported).
    They become effectively ignored by (will not show up on) the type_model.

    **This function should be used with caution, especially in production environments.
    Take care to execute schema modifications in a single context (i.e. not concurrently with other clients).**

    *There are plans to guard schema-modifying functions with an environment-driven conditional.*
    Nz)Types must be derived from base UserType.r(   )r5   r^   r   r   ri   )r}   
type_modelr)   r   r   r   	sync_type2  s
   
r   c                    s  |pt   |j D ]#}g }t||  fdd|D D ]}t| | |d  | qq
| }d| |f }t|}	|	j	j
|  }
|
j}||vrnttd| |d| t|| }t||d |	| | |j| |d d S || }|j}t  }|j D ]C}||j |j|vrtd|| |d q}|j||j }||jkrtd| |d}|||j||j}t| t| q}|j| |d t|t|krttd	| |d| d S ||}|rtd
| |d}t||| d S d S )Nc                    rQ   r   r   rR   syncd_sub_typesr   r   rW   M  rX   z_sync_type.<locals>.<listcomp>r(   z%s.%szsync_type creating new type %srY   zALTER TYPE {0} ADD {1}z~Existing user type {0} has field "{1}" with a type ({2}) differing from the model user type ({3}). UserType should be updated.z'Type %s did not require synchronizationz.Type %s has fields not referenced by model: %s) rf   _fieldsr<   r   rh   ri   rp   	type_namer	   r   r   
user_typesr*   rj   r
   get_create_typer   refresh_user_type_metadataregister_for_keyspacefield_namesro   r6   rw   field_typesrZ   rr   rs   rt   ru   lenr+   rx   )r}   r   omit_subtypesr)   fieldr   r   r   type_name_qualifiedr0   rI   defined_typescql	type_metadefined_fieldsr   
field_typer~   r   r   r   r   ri   G  sX   






ri   c                 C   s<   t ||  dd | j D dd | j D }| S )Nc                 s       | ]}|j V  qd S r3   r   )rS   fr   r   r   	<genexpr>      z"get_create_type.<locals>.<genexpr>c                 s   r   r3   )rr   )rS   vr   r   r   r     r   )r   r   r   r   r<   r-   )r   rI   r   r   r   r   r   |  s   r   c              	      s   |   }d|g}g g  g  fdd}| j D ]\}}|| qdd r7dd  p8d |ddg7 }g }dd	 | j D }|r_|d
d| |tj	
| jpgi 7 }|rw|dd|g7 }d|S )NzCREATE TABLE {0}c                    s<   |   }| jr| jrn }|d| j | d S )Nz"{0}")rw   rv   r   appendr6   ro   )r   skeysckeyspkeysqtypesr   r   
add_column  s
   z%_get_create_table.<locals>.add_columnr   r   r   z({0})c                 S   s    g | ]}d  |j|jpdqS )z	"{0}" {1}ASC)r6   ro   clustering_orderr   r   r   r   rW     s     z%_get_create_table.<locals>.<listcomp>zCLUSTERING ORDER BY ({0})zWITH {0} AND r]   )r`   r6   rg   rn   r   rz   r   r<   r   TableMetadataV3_make_option_strings__options__)rM   ks_table_namequery_stringsr   r   r   property_strings_orderr   r   r   rk     s$   
*
rk   c                 C   s.   t |}|  }|  }|jj| j| }|S r3   )r	   rb   ra   r   r   re   )rM   r)   r0   ksr@   r   r   r   _get_table_metadata  s
   r   c                 C   sp   i }| D ]1}| d\}}|d}|dkr+|||dd  dd}t|}n| }||| < q|S )N={r   }   '")splitfindrfindreplacejsonloadsstrip)option_stringsrE   optionr   valueir   r   r   _options_map_from_strings  s   
r   c              	   C   sV  |   }td||d}t||  | jpi }t| |d}t||j}t	|}t
j|}t	|}i }	| D ]U\}
}z||
 }W n tyZ   td||d}t||
| f w t|tri||krh||	|
< q8z| D ]\}}|| |kr~||	|
<  nqnW q8 ty   ||	|
< Y q8w |	rdt
j|	}d|  |}t||d dS dS )	a
  Updates the table options for the given model if necessary.

    :param model: The model to update.
    :param connection: Name of the connection to use

    :return: `True`, if the options were modified in Cassandra,
        `False` otherwise.
    :rtype: bool
    z"Checking %s for option differencesrY   r(   z-Invalid table option: '%s'; known options: %sr   zALTER TABLE {0} WITH {1}TF)rb   r
   r*   rj   r   r   rf   r   rE   r   r   r   rn   rd   r   r   rl   rz   r6   r`   r   )rM   r)   r}   r~   model_optionsr   existing_option_stringsexisting_optionsmodel_option_stringsupdate_optionsr   r   existing_valuekr   rE   r   r   r   r   ry     sJ   


ry   c              	   C   rG   )a  
    Drops the table indicated by the model, if it exists.

    If `keyspaces` is specified, the table will be dropped for all specified keyspaces. Note that the `Model.__keyspace__` is ignored in that case.

    If `connections` is specified, the table will be synched for all specified connections. Note that the `Model.__connection__` is ignored in that case.
    If not specified, it will try to get the connection from the Model.


    **This function should be used with caution, especially in production environments.
    Take care to execute schema modifications in a single context (i.e. not concurrently with other clients).**

    *There are plans to guard schema-modifying functions with an environment-driven conditional.*
    rH   r(   N)r   r   rJ   _drop_tablerL   r   r   r   
drop_table  s   
r   c                 C   sr   t  sd S |p
|  }t|j}|  }|  }z|j| j|  td	| 
 |d W d S  ty8   Y d S w )NzDROP TABLE {0};r(   )r5   rc   r	   r   rb   ra   r   re   r   r6   r`   rd   )rM   r)   metar}   r|   r   r   r   r   
  s   
r   c                  C   s*   t tstd } t|  t|  dS )Nz| environment variable is not set. Future versions of this package will require this variable to enable management functions.T)osgetenvr   rs   rt   r*   ru   )r~   r   r   r   r5     s
   


r5   )TNr3   )NN)1collectionsr   r   loggingr   rs   	itertoolsr   	cassandrar   cassandra.cqlenginer   r   r   cassandra.cqlengine.connectionr   r	   r
   cassandra.cqlengine.modelsr   cassandra.cqlengine.namedr   cassandra.cqlengine.usertyper   r   r   	getLogger__name__r*   r   r   r#   r&   r!   r9   rF   rP   rK   rm   r   ri   r   rk   r   r   ry   r   r   r5   r   r   r   r   <module>   sH   







b

5
&	

2
