U
    Šfj�  ã                   @   sä   d dl mZ d dlmZmZmZ d dlmZmZm	Z	 d dl
mZ zd dlZW n ek
rh   d dlZY nX zHd dlmZ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 W n ek
rÎ   ed	ƒ‚Y nX G d
d„ deƒZdS )é    )Úabsolute_import)ÚBaseJobStoreÚJobLookupErrorÚConflictingIdError)Ú	maybe_refÚdatetime_to_utc_timestampÚutc_timestamp_to_datetime)ÚJobN)	Úcreate_engineÚTableÚColumnÚMetaDataÚUnicodeÚFloatÚLargeBinaryÚselectÚand_)ÚIntegrityError)Únullz0SQLAlchemyJobStore requires SQLAlchemy installedc                       sž   e Zd ZdZddddejddf‡ fdd„	Z‡ fdd„Zdd	„ Zd
d„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z‡  ZS ) ÚSQLAlchemyJobStorea¸  
    Stores jobs in a database table using SQLAlchemy.
    The table will be created if it doesn't exist in the database.

    Plugin alias: ``sqlalchemy``

    :param str url: connection string (see
        :ref:`SQLAlchemy documentation <sqlalchemy:database_urls>` on this)
    :param engine: an SQLAlchemy :class:`~sqlalchemy.engine.Engine` to use instead of creating a
        new one based on ``url``
    :param str tablename: name of the table to store jobs in
    :param metadata: a :class:`~sqlalchemy.schema.MetaData` instance to use instead of creating a
        new one
    :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the
        highest available
    :param str tableschema: name of the (existing) schema in the target database where the table
        should be
    :param dict engine_options: keyword arguments to :func:`~sqlalchemy.create_engine`
        (ignored if ``engine`` is given)
    NZapscheduler_jobsc              
      s’   t t| ƒ ¡  || _t|ƒp tƒ }|r2t|ƒ| _n |rJt|f|pBi Ž| _ntdƒ‚t	||t
dtdƒdd�t
dtdƒdd�t
d	td
d�|d�| _d S )Nz%Need either "engine" or "url" definedÚidé¿   T)Zprimary_keyÚnext_run_timeé   )ÚindexÚ	job_stateF)Znullable)Zschema)Úsuperr   Ú__init__Úpickle_protocolr   r   Úenginer
   Ú
ValueErrorr   r   r   r   r   Újobs_t)ÚselfÚurlr   Z	tablenameÚmetadatar   ZtableschemaZengine_options©Ú	__class__© úD/tmp/pip-unpacked-wheel-3wcy9vrk/apscheduler/jobstores/sqlalchemy.pyr   +   s      ûzSQLAlchemyJobStore.__init__c                    s&   t t| ƒ ||¡ | j | jd¡ d S )NT)r   r   Ústartr!   Úcreater   )r"   Z	schedulerÚaliasr%   r'   r(   r)   B   s    zSQLAlchemyJobStore.startc              
   C   s`   t | jjjƒ | jjj|k¡}| j ¡ �.}| |¡ 	¡ }|rF|  
|¡nd W  5 Q R £ S Q R X d S ©N)r   r!   Úcr   Úwherer   r   ÚbeginÚexecuteÚscalarÚ_reconstitute_job)r"   Újob_idÚ
selectableÚ
connectionr   r'   r'   r(   Ú
lookup_jobF   s    zSQLAlchemyJobStore.lookup_jobc                 C   s   t |ƒ}|  | jjj|k¡S r,   )r   Ú	_get_jobsr!   r-   r   )r"   ÚnowÚ	timestampr'   r'   r(   Úget_due_jobsL   s    zSQLAlchemyJobStore.get_due_jobsc              
   C   sj   t | jjjƒ | jjjtƒ k¡ | jjj¡ d¡}| j 	¡ �$}| 
|¡ ¡ }t|ƒW  5 Q R £ S Q R X d S )Né   )r   r!   r-   r   r.   r   Úorder_byÚlimitr   r/   r0   r1   r   )r"   r4   r5   r   r'   r'   r(   Úget_next_run_timeP   s    ÿþþz$SQLAlchemyJobStore.get_next_run_timec                 C   s   |   ¡ }|  |¡ |S r,   )r7   Z_fix_paused_jobs_sorting)r"   Újobsr'   r'   r(   Úget_all_jobsX   s    
zSQLAlchemyJobStore.get_all_jobsc              	   C   sx   | j  ¡ jf |jt|jƒt | ¡ | j	¡dœŽ}| j
 ¡ �4}z| |¡ W n tk
rh   t|jƒ‚Y nX W 5 Q R X d S )N)r   r   r   )r!   ÚinsertÚvaluesr   r   r   ÚpickleÚdumpsÚ__getstate__r   r   r/   r0   r   r   )r"   ÚjobrA   r5   r'   r'   r(   Úadd_job]   s    ýzSQLAlchemyJobStore.add_jobc              	   C   sv   | j  ¡ jf t|jƒt | ¡ | j¡dœŽ 	| j j
j|jk¡}| j ¡ �$}| |¡}|jdkrht|jƒ‚W 5 Q R X d S )N)r   r   r   )r!   ÚupdaterB   r   r   rC   rD   rE   r   r.   r-   r   r   r/   r0   Úrowcountr   )r"   rF   rH   r5   Úresultr'   r'   r(   Ú
update_jobi   s    þý

zSQLAlchemyJobStore.update_jobc              	   C   sP   | j  ¡  | j jj|k¡}| j ¡ �"}| |¡}|jdkrBt	|ƒ‚W 5 Q R X d S )Nr   )
r!   Údeleter.   r-   r   r   r/   r0   rI   r   )r"   r3   rL   r5   rJ   r'   r'   r(   Ú
remove_jobs   s
    

zSQLAlchemyJobStore.remove_jobc              	   C   s.   | j  ¡ }| j ¡ �}| |¡ W 5 Q R X d S r,   )r!   rL   r   r/   r0   )r"   rL   r5   r'   r'   r(   Úremove_all_jobsz   s    
z"SQLAlchemyJobStore.remove_all_jobsc                 C   s   | j  ¡  d S r,   )r   Zdispose©r"   r'   r'   r(   Úshutdown   s    zSQLAlchemyJobStore.shutdownc                 C   s:   t  |¡}| |d< t t¡}| |¡ | j|_| j|_|S )NZjobstore)rC   Úloadsr	   Ú__new__Ú__setstate__Z
_schedulerÚ_aliasZ_jobstore_alias)r"   r   rF   r'   r'   r(   r2   ‚   s    


z$SQLAlchemyJobStore._reconstitute_jobc              
   G   sÞ   g }t | jjj| jjjƒ | jjj¡}|r8| t|Ž ¡n|}t	ƒ }| j
 ¡ �ˆ}| |¡D ]L}z| |  |j¡¡ W qX tk
r¢   | j d|j¡ | |j¡ Y qXX qX|rÐ| j ¡  | jjj |¡¡}| |¡ W 5 Q R X |S )Nz)Unable to restore job "%s" -- removing it)r   r!   r-   r   r   r<   r   r.   r   Úsetr   r/   r0   Úappendr2   ÚBaseExceptionZ_loggerÚ	exceptionÚaddrL   Zin_)r"   Z
conditionsr?   r4   Zfailed_job_idsr5   ÚrowrL   r'   r'   r(   r7   ‹   s"    ÿzSQLAlchemyJobStore._get_jobsc                 C   s   d| j j| jjf S )Nz<%s (url=%s)>)r&   Ú__name__r   r#   rO   r'   r'   r(   Ú__repr__    s    zSQLAlchemyJobStore.__repr__)r[   Ú
__module__Ú__qualname__Ú__doc__rC   ÚHIGHEST_PROTOCOLr   r)   r6   r:   r>   r@   rG   rK   rM   rN   rP   r2   r7   r\   Ú__classcell__r'   r'   r%   r(   r      s&     ÿ
	r   )Ú
__future__r   Zapscheduler.jobstores.baser   r   r   Zapscheduler.utilr   r   r   Zapscheduler.jobr	   ÚcPicklerC   ÚImportErrorZ
sqlalchemyr
   r   r   r   r   r   r   r   r   Zsqlalchemy.excr   Zsqlalchemy.sql.expressionr   r   r'   r'   r'   r(   Ú<module>   s   ,