
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
U
    SW]                     @   s   d Z ddlmZ ddlZddlZddlT 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
 dd
lmZ G dd deZdd ZG dd deZG dd deZdZG dd dedeZG dd deZG dd deZdd ZdS )a
  
Lightweight schema migrations.

NOTE: Currently tested with SQLite and Postgresql. MySQL may be missing some
features.

Example Usage
-------------

Instantiate a migrator:

    # Postgres example:
    my_db = PostgresqlDatabase(...)
    migrator = PostgresqlMigrator(my_db)

    # SQLite example:
    my_db = SqliteDatabase('my_database.db')
    migrator = SqliteMigrator(my_db)

Then you will use the `migrate` function to run various `Operation`s which
are generated by the migrator:

    migrate(
        migrator.add_column('some_table', 'column_name', CharField(default=''))
    )

Migrations are not run inside a transaction, so if you wish the migration to
run in a transaction you will need to wrap the call to `migrate` in a
transaction block, e.g.:

    with my_db.transaction():
        migrate(...)

Supported Operations
--------------------

Add new field(s) to an existing model:

    # Create your field instances. For non-null fields you must specify a
    # default value.
    pubdate_field = DateTimeField(null=True)
    comment_field = TextField(default='')

    # Run the migration, specifying the database table, field name and field.
    migrate(
        migrator.add_column('comment_tbl', 'pub_date', pubdate_field),
        migrator.add_column('comment_tbl', 'comment', comment_field),
    )

Renaming a field:

    # Specify the table, original name of the column, and its new name.
    migrate(
        migrator.rename_column('story', 'pub_date', 'publish_date'),
        migrator.rename_column('story', 'mod_date', 'modified_date'),
    )

Dropping a field:

    migrate(
        migrator.drop_column('story', 'some_old_field'),
    )

Making a field nullable or not nullable:

    # Note that when making a field not null that field must not have any
    # NULL values present.
    migrate(
        # Make `pub_date` allow NULL values.
        migrator.drop_not_null('story', 'pub_date'),

        # Prevent `modified_date` from containing NULL values.
        migrator.add_not_null('story', 'modified_date'),
    )

Renaming a table:

    migrate(
        migrator.rename_table('story', 'stories_tbl'),
    )

Adding an index:

    # Specify the table, column names, and whether the index should be
    # UNIQUE or not.
    migrate(
        # Create an index on the `pub_date` column.
        migrator.add_index('story', ('pub_date',), False),

        # Create a multi-column index on the `pub_date` and `status` fields.
        migrator.add_index('story', ('pub_date', 'status'), False),

        # Create a unique index on the category and title fields.
        migrator.add_index('story', ('category_id', 'title'), True),
    )

Dropping an index:

    # Specify the index name.
    migrate(migrator.drop_index('story', 'story_pub_date_status'))
    )
namedtupleN)*)CommaClause)EnclosedClauseEntity)
Expression)Node)OPc                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )	Operationz/Encapsulate a single schema altering operation.c                 O   s   || _ || _|| _|| _d S N)migratormethodargskwargs)selfr   r   r   r    r   D/opt/alt/python38/lib64/python3.8/site-packages/playhouse/migrate.py__init__u   s    zOperation.__init__c                 C   s   | j j }||S r   )r   databasecompiler
parse_node)r   noder   r   r   r   _parse_node{   s    zOperation._parse_nodec                 C   s"   |  |\}}| jj|| d S r   )r   r   r   execute_sql)r   r   sqlparamsr   r   r   execute   s    zOperation.executec                 C   sP   t |tr| | n6t |tr*|  n"t |ttfrL|D ]}| | q<d S r   )
isinstancer	   r   r   runlisttuple_handle_result)r   resultitemr   r   r   r"      s    


zOperation._handle_resultc                 C   s2   | j  }d|d< | t| j| j| j| d S )NTgenerate)r   copyr"   getattrr   r   r   )r   r   r   r   r   r      s
    
zOperation.runN)	__name__
__module____qualname____doc__r   r   r   r"   r   r   r   r   r   r   s   s   	r   c                    s   t   fdd}|S )Nc                    s4   | dd}|r  | f||S t|  jf||S )Nr%   F)popr   r(   )r   r   r   r%   fnr   r   inner   s    zoperation.<locals>.inner)	functoolswraps)r.   r/   r   r-   r   	operation   s    r2   c                   @   s   e Zd ZdZdZdd Zedd Zedd Z	edd	 Z
d
d Zedd Zedd Zedd Zed$ddZedd Zdd Zedd Zedd Zedd Zed%dd Zed!d" Zd#S )&SchemaMigratorFc                 C   s
   || _ d S r   )r   )r   r   r   r   r   r      s    zSchemaMigrator.__init__c                 C   s0   t |trt|S t |tr$t|S t|S d S r   )r   PostgresqlDatabasePostgresqlMigratorMySQLDatabaseMySQLMigratorSqliteMigrator)clsr   r   r   r   from_database   s
    

zSchemaMigrator.from_databasec                 C   sJ   |j }t|r| }ttdt|tdtt|tjt|	|ddS )NUPDATESETT)flat)
defaultcallableClauseSQLr   r   r
   EQParamdb_value)r   tablecolumn_namefieldr>   r   r   r   apply_default   s    zSchemaMigrator.apply_defaultc                 C   sj   |j d }|_ | |_|_| j |}||_ tdt|td|g}t|t	rb|
| | t| S )NTALTER TABLEz
ADD COLUMN)nullname	db_columnr   r   field_definitionrA   r   r   ForeignKeyFieldextendget_inline_fk_sqlr@   )r   rE   rF   rG   Z
field_nullZfield_clausepartsr   r   r   alter_add_column   s    
zSchemaMigrator.alter_add_columnc                 C   s$   t dt|jjjtt|jjgS )N
REFERENCES)rA   r   	rel_model_metadb_tabler   to_fieldrL   r   rG   r   r   r   rP      s    z SchemaMigrator.get_inline_fk_sqlc                 C   s   t d S r   NotImplementedError)r   rE   rF   rG   r   r   r   add_foreign_key_constraint   s    z)SchemaMigrator.add_foreign_key_constraintc                 C   s   |j s|jd krtd| t|t}|r8|js8td| |||g}|j sn|| |||| 	||g |r| j
r|| |||jjj|jj |S )Nz!%s is not null but has no defaultz'Foreign keys must specify a `to_field`.)rJ   r>   
ValueErrorr   rN   rW   rR   rO   rH   add_not_nullexplicit_create_foreign_keyappendr[   rT   rU   rV   rL   )r   rE   rF   rG   is_foreign_key
operationsr   r   r   
add_column   s*    



zSchemaMigrator.add_columnc                 C   s   t d S r   rY   r   rE   rF   r   r   r   drop_foreign_key_constraint   s    z*SchemaMigrator.drop_foreign_key_constraintTc                 C   sr   t dt|t dt|g}|r.|t d t| }dd | j|D }||krj| jrj| |||gS |S d S )NrI   zDROP COLUMNCASCADEc                 S   s   g | ]
}|j qS r   column).0foreign_keyr   r   r   
<listcomp>  s   z.SchemaMigrator.drop_column.<locals>.<listcomp>)rA   r   r_   r@   r   get_foreign_keysexplicit_delete_foreign_keyrd   )r   rE   rF   cascadenodesZdrop_column_nodeZ
fk_columnsr   r   r   drop_column   s     

zSchemaMigrator.drop_columnc                 C   s*   t tdt|tdt|tdt|S )NrI   zRENAME COLUMNTOr@   rA   r   )r   rE   old_namenew_namer   r   r   rename_column  s    zSchemaMigrator.rename_columnc                 C   s   t dt|t dt|gS )NrI   zALTER COLUMN)rA   r   r   rE   rg   r   r   r   _alter_column  s
    zSchemaMigrator._alter_columnc                 C   s"   |  ||}|td t| S )NzSET NOT NULLrv   r_   rA   r@   r   rE   rg   rn   r   r   r   r]   "  s    zSchemaMigrator.add_not_nullc                 C   s"   |  ||}|td t| S )NzDROP NOT NULLrw   rx   r   r   r   drop_not_null(  s    zSchemaMigrator.drop_not_nullc                 C   s   t tdt|tdt|S )NrI   z	RENAME TOrq   r   rr   rs   r   r   r   rename_table.  s    zSchemaMigrator.rename_tablec                 C   sL   | j  }|rdnd}tt|t|||tdt|tdd |D  S )NzCREATE UNIQUE INDEXzCREATE INDEXONc                 S   s   g | ]}t |qS r   r   rh   rg   r   r   r   rj   ?  s     z,SchemaMigrator.add_index.<locals>.<listcomp>)r   r   r@   rA   r   
index_namer   )r   rE   columnsuniquer   	statementr   r   r   	add_index6  s    
zSchemaMigrator.add_indexc                 C   s   t tdt|S )N
DROP INDEXrq   r   rE   r~   r   r   r   
drop_indexA  s    zSchemaMigrator.drop_indexN)T)F)r(   r)   r*   r^   rl   r   classmethodr:   r2   rH   rR   rP   r[   rb   rd   ro   rt   rv   r]   ry   r{   r   r   r   r   r   r   r3      s>   




!

	



r3   c                       s(   e Zd Zdd Ze fddZ  ZS )r5   c                 C   s&   d}| j || }dd | D S )Nai  
            SELECT pg_attribute.attname
            FROM pg_index, pg_class, pg_attribute
            WHERE
                pg_class.oid = '%s'::regclass AND
                indrelid = pg_class.oid AND
                pg_attribute.attrelid = pg_class.oid AND
                pg_attribute.attnum = any(pg_index.indkey) AND
                indisprimary;
        c                 S   s   g | ]}|d  qS r   r   )rh   rowr   r   r   rj   U  s     z;PostgresqlMigrator._primary_key_columns.<locals>.<listcomp>)r   r   fetchall)r   Ztblquerycursorr   r   r   _primary_key_columnsI  s    
z'PostgresqlMigrator._primary_key_columnsc           
         s   |  |}tt| }|j||ddg}t|dkrd||d f }d}| j||f}t| rd||d f }	|	|j||	dd |S )NT)r%      z	%s_%s_seqr   z
                SELECT 1
                FROM information_schema.sequences
                WHERE LOWER(sequence_name) = LOWER(%s)
            )
r   superr5   r{   lenr   r   boolfetchoner_   )
r   rr   rs   Zpk_namesZParentClassra   Zseq_namer   r   Znew_seq_name	__class__r   r   r{   W  s     

  zPostgresqlMigrator.rename_table)r(   r)   r*   r   r2   r{   __classcell__r   r   r   r   r5   H  s   r5   )rK   
definitionrJ   pkr>   extrac                   @   s:   e Zd Zedd Zedd Zedd Zd
dd	ZdS )MySQLColumnc                 C   s
   | j dkS )NZPRIr   r   r   r   r   is_pkr  s    zMySQLColumn.is_pkc                 C   s
   | j dkS )NZUNIr   r   r   r   r   	is_uniquev  s    zMySQLColumn.is_uniquec                 C   s
   | j dkS )NYES)rJ   r   r   r   r   is_nullz  s    zMySQLColumn.is_nullNc                 C   s   |d kr| j }|d kr| j}t|t| jg}| jrB|td |rV|td n|td | jrx|td | jr|t| j t	| S )NZUNIQUENULLNOT NULLzPRIMARY KEY)
r   rK   r   rA   r   r   r_   r   r   r@   )r   rF   r   rQ   r   r   r   r   ~  s"    zMySQLColumn.sql)NN)r(   r)   r*   propertyr   r   r   r   r   r   r   r   r   q  s   


r   Z_Columnc                   @   s   e Zd ZdZdZedd Zdd Zedd Zdd	 Z	ed
d Z
dd Zedd Zedd Zedd Zedd ZdS )r7   Tc                 C   s   t tdt|tdt|S )NzRENAME TABLErp   rq   rz   r   r   r   r{     s    zMySQLMigrator.rename_tablec                 C   s@   | j d| }| }|D ]}t| }|j|kr|  S qdS )NzDESCRIBE %s;F)r   r   r   r   rK   )r   rE   rF   r   rowsr   rg   r   r   r   _get_column_definition  s    

z$MySQLMigrator._get_column_definitionc                 C   sR   d|||f }t tdt|tdt|tdtt|tdt|tt|	S )Nzfk_%s_%s_refs_%srI   zADD CONSTRAINTzFOREIGN KEYrS   )r@   rA   r   r   )r   rE   rF   relZ
rel_column
constraintr   r   r   r[     s    

z(MySQLMigrator.add_foreign_key_constraintc                 C   s6   | j d||f}| }|s.td||f |d S )NzSELECT constraint_name FROM information_schema.key_column_usage WHERE table_schema = DATABASE() AND table_name = %s AND column_name = %s;z=Unable to find foreign key constraint for "%s" on table "%s".r   )r   r   r   AttributeError)r   rE   rF   r   r#   r   r   r   get_foreign_key_constraint  s    z(MySQLMigrator.get_foreign_key_constraintc              	   C   s&   t tdt|tdt| ||S )NrI   zDROP FOREIGN KEY)r@   rA   r   r   rc   r   r   r   rd     s    z)MySQLMigrator.drop_foreign_key_constraintc                 C   s   g S r   r   rX   r   r   r   rP     s    zMySQLMigrator.get_inline_fk_sqlc                 C   s.   |  ||}ttdt|td|jddS )NrI   MODIFYFr   )r   r@   rA   r   r   ru   r   r   r   r]     s    
zMySQLMigrator.add_not_nullc                 C   s<   |  ||}|jrtdttdt|td|jddS )NzPrimary keys can not be nullrI   r   Tr   )r   r   r\   r@   rA   r   r   ru   r   r   r   ry     s    
zMySQLMigrator.drop_not_nullc           	      C   s   t dd | j|D }||k}| ||}ttdt|tdt||j|d}|r|| }| |||| 	|||j
|jgS |S d S )Nc                 s   s   | ]}|j |fV  qd S r   rf   )rh   fkr   r   r   	<genexpr>  s   z.MySQLMigrator.rename_column.<locals>.<genexpr>rI   ZCHANGE)rF   )dictr   rk   r   r@   rA   r   r   rd   r[   
dest_tabledest_column)	r   rE   rr   rs   Z
fk_objectsr`   rg   Zrename_clauseZfk_metadatar   r   r   rt     s0    



zMySQLMigrator.rename_columnc                 C   s   t tdt|tdt|S )Nr   r|   rq   r   r   r   r   r     s    zMySQLMigrator.drop_indexN)r(   r)   r*   r^   rl   r2   r{   r   r[   r   rd   rP   r]   ry   rt   r   r   r   r   r   r7     s&   
	





r7   c                   @   s   e Zd ZdZedZedZedZedej	Z
dd Zdd	 Zed
d Zdd ZedddZedd Zedd Zedd ZdS )r8   z
    SQLite supports a subset of ALTER TABLE queries, view the docs for the
    full details http://sqlite.org/lang_altertable.html
    z(.+?)\((.+)\)z(?:[^,(]|\([^)]*\))+z["`']?([\w]+)z FOREIGN KEY\s+\("?([\w]+)"?\)\s+c                 C   s    | j d| }dd |jD S )Nzselect * from "%s" limit 1c                 S   s   g | ]}|d  qS r   r   )rh   r$   r   r   r   rj     s     z4SqliteMigrator._get_column_names.<locals>.<listcomp>)r   r   descriptionr   rE   resr   r   r   _get_column_names  s    z SqliteMigrator._get_column_namesc                 C   s   | j dd| g}| S )NzBselect name, sql from sqlite_master where type=? and LOWER(name)=?rE   )r   r   lowerr   r   r   r   r   _get_create_table  s
    
z SqliteMigrator._get_create_tablec              	      s  t dd j|D }| |kr6td||f |\}}j|}j| t	dd|}j
| \}}j|}	dd |	D }
g }g }g }|
D ]}j| \}||kr
|||}|r6|| || j| \}|| q|| | ds|| || qtt||}|| d	d
 } shdd
 }n |kr fdd
}g }|D ]F}j|}|d k	r| d |kr||}|r|| q|d }td| tj}|	d| |}d|}ttdt|td| |f g}ttdt|tdd |D  tdtdd |D  tdt|}|| |ttdt| | || t!dd
 |D ]R}||j"kr|t|j# n. r$|j#| }|d k	r|t| q|S )Nc                 s   s   | ]}|j  V  qd S r   )rK   r   r}   r   r   r   r      s   z0SqliteMigrator._update_column.<locals>.<genexpr>z"Column "%s" does not exist on "%s"z\s+ c                 S   s   g | ]}|  qS r   striprh   colr   r   r   rj   8  s     z1SqliteMigrator._update_column.<locals>.<listcomp>)ZforeignZprimaryc                 S   s   | S r   r   
column_defr   r   r   <lambda>S      z/SqliteMigrator._update_column.<locals>.<lambda>c                 S   s   d S r   r   r   r   r   r   r   V  r   c                    s   j d  | S )NzFOREIGN KEY ("%s") )fk_resubr   
new_columnr   r   r   r   Y  s   r   Z__tmp__z
("?)%s("?)z\1%s\2, zDROP TABLE IF EXISTSz%s (%s)zINSERT INTOc                 S   s   g | ]}t |qS r   r   r   r   r   r   rj   v  s     SELECTc                 S   s   g | ]}t |qS r   r   r   r   r   r   rj   x  s     FROMz
DROP TABLEc                 S   s   | j S r   )r   )idxr   r   r   r     r   )%setr   get_columnsr   r\   r   get_indexesrk   rer   	column_researchgroupscolumn_split_refindallcolumn_name_rematchr_   
startswithr   zipgetr   compileIjoinr@   rA   r   r   r   r   r{   filterr   r   
_fix_index)r   rE   column_to_updater.   r   create_tableindexesZ
raw_createZraw_columnsZsplit_columnsZcolumn_defsZnew_column_defsZnew_column_namesZoriginal_column_namesr   rF   Znew_column_defZoriginal_to_newZfk_filter_fnZcleaned_columnsr   Z
temp_tableZrgxcreatequeriesZpopulate_tableindexr   r   r   r   _update_column  s    













zSqliteMigrator._update_columnc           
      C   s   | |}t|dkr"|||S |dd\}}t| |dkrXd||||f S |ddd  d}dd	 |D }g }|D ]2}	td
| |	rt|	t|d   }	||	 qd|ddd |D f S )N   (r   z%s(%s)r   ,c                 S   s   g | ]}| d qS )z"`[]' r   )rh   partr   r   r   rj     s     z-SqliteMigrator._fix_index.<locals>.<listcomp>z%s(?:['"`\]]?\s|$)z%s(%s)r   c                 s   s   | ]}d | V  qdS )z"%s"Nr   )rh   cr   r   r   r     s     z,SqliteMigrator._fix_index.<locals>.<genexpr>)	splitr   replacersplitr   r   Znew_columner_   r   )
r   r   r   r   rQ   lhsrhsr   cleanrg   r   r   r   r     s    
zSqliteMigrator._fix_indexTc                 C   s   |  ||dd S )Nc                 S   s   d S r   r   )abr   r   r   r     r   z,SqliteMigrator.drop_column.<locals>.<lambda>r   )r   rE   rF   rm   r   r   r   ro     s    zSqliteMigrator.drop_columnc                    s    fdd}|  |||S )Nc                    s   | |  S r   r   rF   r   rs   r   r   _rename  s    z-SqliteMigrator.rename_column.<locals>._renamer   )r   rE   rr   rs   r   r   r   r   rt     s    zSqliteMigrator.rename_columnc                 C   s   dd }|  |||S )Nc                 S   s   |d S )Nz	 NOT NULLr   r   r   r   r   _add_not_null  s    z2SqliteMigrator.add_not_null.<locals>._add_not_nullr   )r   rE   rg   r   r   r   r   r]     s    zSqliteMigrator.add_not_nullc                 C   s   dd }|  |||S )Nc                 S   s   | ddS )Nr    r   r   r   r   r   _drop_not_null  s    z4SqliteMigrator.drop_not_null.<locals>._drop_not_nullr   )r   rE   rg   r   r   r   r   ry     s    zSqliteMigrator.drop_not_nullN)T)r(   r)   r*   r+   r   r   r   r   r   r   r   r   r   r2   r   r   ro   rt   r]   ry   r   r   r   r   r8   	  s$   



p

r8   c                  O   s   | D ]}|   qd S r   )r   )ra   r   r2   r   r   r   migrate  s    r   )r+   collectionsr   r0   r   peeweer   r   r   r   r	   r
   objectr   r2   r3   r5   Z_column_attributesr   r7   r8   r   r   r   r   r   <module>   s*   e 	 -'"v =