U
    gydQ                     @   sP  d dl Z d dlZd dlZd dlZd dlZd dlmZmZ d dlm	Z	 d dl
mZ d dlZd dlmZ d dlZd dlmZ d dlmZ dd	lmZ i Zd-d
dZdd Zdd Zdd Zd.ddZdd Zdd Zd/ddZdd Zdd Z G dd dZ!G d d! d!Z"G d"d# d#e"Z#G d$d% d%e"Z$d0d'd(Z%G d)d* d*Z&G d+d, d,Z'dS )1    N)defaultdict
namedtuple)deepcopy)List)g)fields)config   )	BaseModelc                    s   ddl mm ddl m  ddlm} t| |rL|d krD| jjj}| j	} n|d kr\| jj}G  fddd|j
  || | S )Nr   )date	timedelta)datetime)Queryc                       s6   e Zd ZdddZdd Z fddZ  ZS )	z%render_query.<locals>.LiteralCompilerFc                 [   s   |  |j|jS N)render_literal_valuevaluetype)selfZ	bindparamZwithin_columns_clauseZliteral_bindskwargs r   ./data_providers/base.pyvisit_bindparam-   s    z5render_query.<locals>.LiteralCompiler.visit_bindparamc                    s4   t |tr(dd fdd|D  S | S )Nz{%s},c                    s   g | ]} | qS r   )render_array_value.0x	item_typer   r   r   
<listcomp>3   s     zLrender_query.<locals>.LiteralCompiler.render_array_value.<locals>.<listcomp>)
isinstancelistjoinr   )r   valr   r   r   r   r   1   s    
z8render_query.<locals>.LiteralCompiler.render_array_valuec                    sj   t |trt|S t |fr0d|d S t |trXdd fdd|D  S t |S )Nz'%s'z%Y-%m-%d %H:%M:%Sz'{%s}'r   c                    s   g | ]}  |jqS r   )r   r   r   r   type_r   r   r   =   s     zNrender_query.<locals>.LiteralCompiler.render_literal_value.<locals>.<listcomp>)r    intreprstrftimer!   r"   superr   )r   r   r%   )LiteralCompiler	__class__r   r   r   r$   r   r   6   s    

z:render_query.<locals>.LiteralCompiler.render_literal_value)FF)__name__
__module____qualname__r   r   r   __classcell__r   r*   r   r   r   r+   r   r*   +   s
     
r*   )r   r   r   Zsqlalchemy.ormr   r    ZsessionZbinddialect	statementZstatement_compilerZprocess)r3   r2   r   r   r0   r   render_query   s    	

r4   c                 C   s
   t | S )uK   Вернём драйвер по имени источника данных)ds_registryget)ds_namer   r   r   get_ddC   s    r8   c                  C   sf   t rtdd} tj D ]F\}}|ddkrP| dkrHddlm} |} | |d< t||dt |< qdS )uY   Инициализация всех источников данных из конфигаuZ   Источники данных нельзя инициализировать дваждыNzsqlalchemy.poolclass	QueuePoolr   )r9   )name)	r5   	Exceptionr   Zdata_sourcesitemsr6   Zsqlalchemy.poolr9   new_dd)Z
queue_poolr7   	ds_configr9   r   r   r   init_dsH   s    r?   c               	   C   sN   t  D ]@\} }td|   z|  W q tk
rF   td Y qX qdS )u=   Инициализация, миграция схемы БД.zInit DB u        не реализовано.N)r5   r<   printinit_dbNotImplementedError)r7   Zds_ddr   r   r   rA   X   s    rA   c                 C   sf   |  d}|s$|  d}|dkr$d}|s4td|| |jddd\}}t|}t||}|| |d	S )
Nclassr   Z
sqlalchemyz2cmf.data_providers.sqlalchemy:SQLAlchemyDataDriverzDYou must specify valid "type" or "class" in datasource configuration:   )maxsplitr>   r:   )r6   
ValueErrorsplit	importlibimport_modulegetattr)r>   r:   Zdd_mod_classZdd_typeZdd_module_nameZdd_class_nameZ	dd_moduleZdd_classr   r   r   r=   c   s    



r=   c                  C   s   t  D ]} |   qd S r   )r5   valuesbefore_requestddr   r   r   rN   r   s    rN   c                  C   s   t  D ]} |   qd S r   )r5   rM   before_first_requestrO   r   r   r   rQ   x   s    rQ   c                 C   sV   t  D ]H}| r.ttdr$td |  qttdrHt| d |  qd S )NdebugZROLLBACKz COMMIT)r5   rM   hasattrr   rR   rollbackcommit)Z	exceptionrP   r   r   r   commit_all_ds~   s    



rV   c                  C   s*   t  D ]} td|   |   qd S )Nz	ROLLBACK )r5   rM   r   rR   rT   rO   r   r   r   rollback_all_ds   s    rW   c                  C   s(   ddl m}  t D ]}||  qdS )zmake_models hookr   modelsN)cmf.includerY   r5   rM   make_models)rY   rP   r   r   r   r[      s    r[   c                   @   s   e Zd ZdZddd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dd Zd d! Zd"d# Zd$d% Zd&d' ZdS )(BaseDataDriver NrG   c                O   s   || _ || _d S r   )r   r:   )r   r>   r:   _args_kwargsr   r   r   __init__   s    zBaseDataDriver.__init__c                 O   s   d S r   r   r   modelargsr   r   r   r   r6      s    zBaseDataDriver.getc                 O   s   d S r   r   r   instancerc   r   r   r   r   create   s    zBaseDataDriver.createc                 O   s   d S r   r   rd   r   r   r   delete   s    zBaseDataDriver.deletec                 O   s   d S r   r   rd   r   r   r   update   s    zBaseDataDriver.updatec                 O   s   d S r   r   ra   r   r   r   r!      s    zBaseDataDriver.listc                 O   s   d S r   r   ra   r   r   r   count   s    zBaseDataDriver.countc                 C   s   d S r   r   r   r   r   r   rU      s    zBaseDataDriver.commitc                 C   s   d S r   r   rj   r   r   r   rT      s    zBaseDataDriver.rollbackc                 C   s   d S r   r   rj   r   r   r   rN      s    zBaseDataDriver.before_requestc                 C   s   d S r   r   rj   r   r   r   rQ      s    z#BaseDataDriver.before_first_requestc                 C   s   d S r   r   )r   	cmf_modelr   r   r   dp_model   s    zBaseDataDriver.dp_modelc                 C   s   d S r   r   )r   Zsa_modelr   r   r   rk      s    zBaseDataDriver.cmf_modelc                 C   s   d S r   r   )r   Zdp_instancer   r   r   is_instance   s    zBaseDataDriver.is_instancec                 C   s   d S r   r   )r   Zmodels_r   r   r   r[      s    zBaseDataDriver.make_modelsc                 O   s   dS )u,   Вернём кастомный запросNr   r   rc   r   r   r   r   query_deprecated   s    zBaseDataDriver.query_deprecatedc                 C   s   t dS )u2   Создание/миграция схемы БД.NrB   rj   r   r   r   rA      s    zBaseDataDriver.init_dbc                 C   s   dS )u8   Закрываем текущие подключенияNr   rj   r   r   r   close_all_sessions   s    z!BaseDataDriver.close_all_sessions)r,   r-   r.   __doc__r`   r6   rf   rg   rh   r!   ri   rU   rT   rN   rQ   rl   rk   rm   r[   ro   rA   rq   r   r   r   r   r\      s&   r\   c                   @   sF   e Zd Zdd ZdddZdd Zdd	 Zdd
dZedddZ	dS )
BaseMapperc                 C   s   dS )u  
        Вызывать по завершению маппинга всех объектов в запросе, постобработка.
        Обычно должен вызывать тот, кто создал экземпляр маппера.
        Nr   rj   r   r   r   post_mapping_hook   s    zBaseMapper.post_mapping_hookNc                 C   s   t d S r   rp   )r   obj
cmf_entityrb   
model_namefull_fields_loadr   r   r   object_to_cmf   s    zBaseMapper.object_to_cmfc                 C   s   t d S r   rp   )r   rv   ru   r   r   r   cmf_to_object   s    zBaseMapper.cmf_to_objectc                    s~   |sdS  fdd|j D }tdtf|}| |_ |j D ]>}|  dr:d|ddd }t||t|| q:|S )u  
        TODO: создание промежуточного объекта плохо для производительности, нужно маппить напрямую из ResultSet
          да и в целом можно зарефакторить
        Nc                    s6   i | ].}|   d rd|ddd dqS )_sub__rE   N)
startswithr"   rI   )r   field
field_namer   r   
<dictcomp>   s    z4BaseMapper.obj_from_result_query.<locals>.<dictcomp>ZCmfObjr{   r|   rE   )	_fieldsr   objectkeysr}   r"   rI   setattrrL   )r   result_queryr   Z
obj_fieldsresr~   Zattnamer   r   r   obj_from_result_query   s    


z BaseMapper.obj_from_result_queryc                    s    fdd|D S )Nc                    s   g | ]}j | d qS )rb   rx   )ry   )r   ru   rx   rb   r   r   r   r      s     z*BaseMapper.list_to_cmf.<locals>.<listcomp>r   )r   Zlstrx   rb   r   r   r   list_to_cmf   s    zBaseMapper.list_to_cmfc                 C   sB   |s
t  S |dkrt S t|tr&|S t|tr6| S tddS )u   
        :param mapper: тип маппера
        :type mapper: None, str, Mapper subclass, Mapper instance
        :return: экземпляр маппера
        :rtype:  Mapper
        ZsimplezInvalid mapperN)MapperSimpleMapperr    rs   
issubclassrH   )clsmapperr   r   r   
get_mapper   s    

zBaseMapper.get_mapper)NNNN)N)N)
r,   r-   r.   rt   ry   rz   r   r   classmethodr   r   r   r   r   rs      s   

rs   c                       sX   e Zd ZdZe G dd dZeddddgZ fdd	Z	d
d Z
dddZ  ZS )r   u   
    Dataclass as model, для лёгкой сериализации в json
    fill class_name
    TODO fill meta для api, но вероятно это драйвер будет делать, там дешевле
    c                   @   s   e Zd Zdd ZdS )zSimpleMapper.SimpleModelc                 C   s@   t | dr&| j d| j d| j dS | j dt| dd  dS )Nr:   (z: )id)rS   
class_namecoder:   rL   rj   r   r   r   __repr__  s    
z!SimpleMapper.SimpleModel.__repr__N)r,   r-   r.   r   r   r   r   r   SimpleModel  s   r   VirtualInitDatar   rb   
field_listc                    s   t    g | _d S r   )r)   r`   _virtual_init_listrj   r1   r   r   r`     s    
zSimpleMapper.__init__c                 C   s   i }t | jD ]j}||jj}|r.|j|_n|j|jd}|||jj< |jD ](}t||j}d|_	t
|j|j|j qNqg | _dS )uN   Вычислим все запрошенные виртуальные поля)simple_objectN)reversedr   r6   rb   r   r   r   r   rL   _valuer   r   )r   Zcmf_instancesZ	init_dataZcmf_wrapper	field_clsZvirtual_fieldr   r   r   rt      s    

zSimpleMapper.post_mapping_hookNc              	   C   s   ddl m} |s.|s$|jdd }t||}|sDt }|j|_ntd||g }|p\|j	D ]|}|j	
|}	|	svq^|	jr|s|	jdkr||	 q^t|	t	jt	jfrt||	 d}
|
dkrq^|
dkrd}nF|o|
|}|r^t|| dddk	r^| j| |||d	}nq^nq^n(t|	t	jt	jt	jfr6q^nt||d}|dkrNq^t|	t	jr| ||op|
|t||	jd }nLt|	t	jr|r|js|jtjjd
}nt|	t	jr|rt !|}t"||| q^|r| j#tj$|||d |S )u  
        отображение obj -> simple_model
        если cmf_entity не указан, то создадим новый на основе модели cmf_model или её имени model_name
        возвращаем simple_model
        r   rX   rD   uI   Передан cmf_entity в SimpleMapper, вероятно это баг)defaultalways.N_sub__id)rx   tzinfo)r   rb   r   )%rZ   rY   r   rI   rL   r   r   r   rH   r   r6   virtual	load_modeappendr   CmfRelationCmfGenericRelationid_fieldnamery   r   
CmfM2MBaseCmfBackrefBaseCmfDateRangeCmfObjectListr   CmfDateTimer   replacer   timezoneutcCmfJsonujsonloadsr   r   r   )r   ru   rv   rb   rw   rx   rY   Zvirtual_fieldsr   r   obj_related_idfield_valuesub_fflr   r   r   ry   3  sl    




 
zSimpleMapper.object_to_cmf)NNNN)r,   r-   r.   rr   dataclassesZ	dataclassr   r   r   r`   rt   ry   r/   r   r   r1   r   r     s   r   c                   @   s   e Zd ZdddZdd ZdS )r   Nc              	   C   s  ddl m} |sB|s2|s(|jdd }t||}|dd}d}nd}|sRt|}|}|r`|}	n
|j }	|	D ]}
|j|
 }sqn|j	r|s|j
dkrt||
}d|_d|_qnt||
d	}t|tjr|d	krqn| ||o||
t||jd }t|tjtjfrt|| d	}|d	kr(qn|dkr8d}n|oF||
}|rnt||
 d
ddkrnt|tjr~|dd n|j}t||d}|r| j| ||
||d}nd}nqnnqnnt|tjtjtjfrqn|d	krqnt|tjr|r|js|jtjjd}t|tjr.|r.t !|}t||
}|rJ|jd	krvt"|t#t$t%tdt&frl||_n
t'||_||_qnd|_(|)  |S )u  
        отображение obj -> cmf_entity
        если cmf_entity не указан, то создадим новый на основе модели cmf_model или её имени model_name
        возвращаем ссылку на cmf_entity
        r   rX   rD   T)emptyFr   N.r   r   r   )*rZ   rY   r   rI   rL   r   r   r   r6   r   r   r   Z_oldr   r   r   r   r   r   rb   ry   r   r   r   r   r   r   r   r   r   r   r   jsonr   r    strr&   floatboolr   Zis_newZmark_exists_in_db)r   ru   rv   rb   rw   rx   rY   Zcmf_is_existsr   r   kr   r~   r   r   r   Z	model_subZ	field_objr   r   r   ry     s    




  


 



zMapper.object_to_cmfc                 C   s   t |}|j D ]\}}t|tjr(qt|tjr6qt|tjrDqt|tjrRqt|tjr`qt|tj	rnqt|tj
r|qt||}t|tjr|jdks|jrq| }|dkrtd| d| d| t||| q|S )N.u%   Попытка update field=Ellipsis  )r   r   r<   r   r   r   ZCmfM2MZCmfGenericM2MZ
CmfBackrefr   ZCmfGenericBackrefrL   r    CmfTyper   r   Z	db_formatr;   r   )r   rv   ru   rb   r   vZvvr   r   r   rz     s2    
zMapper.cmf_to_object)NNNN)r,   r-   r.   ry   rz   r   r   r   r   r     s   
ir   selectc              
   C   s   zdt krttt _W n( tk
r> } z
W Y dS d}~X Y nX t jdtt t jd | d t jd |   d7  < t jd dd t jd d  d7  < dS )uK   
    Глобальный счетчик запросов
    :return:
    profiler_dataNZselect_countr   rE   total)r   r   dictr   r;   
setdefault)actioner   r   r   inc_select_count	  s    r   c                   @   s   e Zd ZdZedZd&ddZedd Z	dddd	d
dZ
dd ZddddZdd Zdd Zdd Zdd Zd'ddZdd Zdddd	ddZddd d!d"Zdd#d$d%ZdS )(DataProvideruV   Объект, связывающий модель с источником данныхz"\b(?P<table>\w+)\.(?P<field>\w+)\bNc                 C   s   || _ || _d | _t| _d S r   )rb   data_source_ddr   Z
mapper_cls)r   r   rb   r   r   r   r`      s    zDataProvider.__init__c                 C   s   | j st| j| _ | j S r   )r   r8   r   rj   r   r   r   data_driver&  s    zDataProvider.data_driverF)no_cacheTECHCOM_nocache
for_updatec          	      O   sP  |rt d| jjp|}| | j||d< tjjj| jj df||}|s^|s^tjj	 rdd}ntjj
|}t  |dkrtjtjjjd|  dS |dk	rtjtjjjd|  |S tjtjjjd|  | jj
| jf|d	|i|}| jjd
kr|S tjjj||| jj | | j|d |
d|
dd |S dS )zF
        :param args:
        :param kwargs:
        :return:
        8   no_cache запрещен и будет удален osvfilterz.getNEmptyzDP: get() cache Empty zDP: get() cache zDP: get() NOcache r   rdiskorder_bygroup_byquery_params)r;   rb   r   _get_filtercmfapp	CMF_CACHEhashr,   cache_is_lockedr6   r   print_debugDEBUGr   r:   add_query_params)	r   r   r   r   rc   r   keycachedb_resr   r   r   r6   ,  s4        zDataProvider.getc                 O   s\   t d | jj|f||}| jjdkr,|S |d krHtjj|d d S tjj|d |S )Ninsertr   rf   )r   r   rf   r:   r   r   r   
invalidate)r   re   rc   r   r   r   r   r   rf   R  s    zDataProvider.create)r   c                O   s   t d | jj|f||}|r(td| jj}| jjdkr@|S |s|ddrd}d|jkrt|j	j
rt|j	rpdnd}tjj|| |S )	Nrh   r   r   r   Tcmf_deletedrg   rf   )r   r   rh   r;   rb   r   r:   r6   r   r   Z
is_changedr   r   r   r   )r   re   r   rc   r   r   r   r   r   r   rh   b  s    zDataProvider.updatec                 O   s   | j j||}|S r   )r   rU   )r   rc   r   retr   r   r   rU   t  s    zDataProvider.commitc                 O   s   | j j||S r   )r   rT   rn   r   r   r   rT   y  s    zDataProvider.rollbackc                 O   s2   | j j||}| j jdkr|S tjj|d |S )u   
        Logical delete. Реализация в провайдере или в модели?
        self.deleted = 1
        self.update()
        r   rg   )r   rg   r:   r   r   r   r   )r   rc   r   r   r   r   r   rg   |  s
    zDataProvider.deletec                    s   | dg }|dkrg }t|tr,t|}|r6|g}|  D ]:\}}||jkrB||= t|tjrl|j	}|
|d|g qB fdd  |}|S )u   
        Преобразуем обычные kwargs в продвинутый фильтр для однообразной логики фильтрования
        :param model:
        :param kwargs:
        :return:
        r   N==c                    s   t | tr fdd| D S t | tr| dkr8tjjjS | dkrdtjsNdt_nttjdt_t	 S | dkrtjszdt_nttjdt_t
 S | S )Nc                    s   g | ]} |qS r   r   )r   i_recursive_params_replacer   r   r     s     zODataProvider._get_filter.<locals>._recursive_params_replace.<locals>.<listcomp>Z__G_CURRENT_USERZ__G_NOWi,  Z__G_DATEip  )r    r!   r   r   Zcurrent_userr   r   Zjscache_timelifeminZnowr   )r   r   r   r   r     s     


z;DataProvider._get_filter.<locals>._recursive_params_replace)r6   r    r   r   r   copyr<   r   r   r   r   )r   rb   r   Zsmart_filterr   r   r   r   r   r     s     


zDataProvider._get_filterANDc                 C   s:  ddl m} tg g g g g d}|rx|D ]P}|dkr4q&|dr\|d d |jkr\|d d }|d |j d|  q&|r|D ]F}	|	dr|	d d |jkr|	d d }	|d |j d|	  q|s|S t|d tr|D ]0}
| j	||
|d	
 D ]\}}|| | qqn|d d
krf| j	||dd  |d d	
 D ]\}}|| | qHn|d dkr t|dks|d dkrtd|d D ]Z}|dkrq|dr|d d |jkr|d d }|d |j d|  qn6t|dkr"d }|d d}|d d}d }d }|d dkrH|S |d |jkr|d }|j|d  }|d }t|dkr|d }nD|d |jkr|d }|j|d  }|d }t|dkr|d }d}|dr|d d |jkr|d d }d}|rN|drN| }|r>|d d |d jkrN|d d }d}|r6|s|dkr|dkr|d }t|ts|g}g }|D ]@}tt|tjr|j}tt|tr|jj}|| q|dkr|d | |dkr|d | |dkr|d | t|tjrP|jdkrP|j|jd d pN|}t|tjr|dkr| D ]>}|s|d |j  |rp|d |j d|  qpt|tjr|dkr| D ]4}| 	||d 
 D ]\}}|| | qq|d |j d|  n|d| ddd |S ) Nr   )	cmf_alertrY   r   parentscache_clusterslistsr   Z_idr   .)parent_oper)r   ORrE   r      )=r   ut   Операция order_by в фильтре должна быть в формате: ["order_by", "=", [поля..]]r	   r   FT)r   r   INr   parentr   Zcache_clusterr   r   rY   EXISTSuP   Ошибка  при выполнении UBQL - неверный запрос. uM    Проверьте правильность введенных данных.)abort)rZ   r   r   endswithr   r   r   r    r!   r   r<   extendlenr;   rI   Zrelated_modelsr   r   r   r   r
   r   ZCmfTUUIDr6   Z
CmfRelBase)r   rb   Z
obj_filterZobj_order_byZobj_group_byr   r   r   r   r   Zfilt_lsr   r#   r~   Zobj_filter0Zobj_filter1Zfield__field_namer   ZoperZfield_is_tuuidZ
_relmodelsZrule_values_dirtyZrule_valuesrvZrmodelr   r   r   r     s    (
 "
 



zDataProvider._query_paramsc                 C   s*  dddddgdddgggdgd	d
dgg g g dgdddgdgdgg g dgdgdddgg dgg g g dgdddgdgddgg g g dgdddgdddggg ddgg g g dgdddggg dgg g g dgdddggg dgg g g dgdddggg dgg g g dgd ddggd!gd"d#gg g g dgd$dd%ggg d&d#gg g g dgd'dd%ggd!gd&d#gg g g dgdddgd(dd)ggg dd*gg g g dgd+ddggg dgg g g dgd,ddggd!gd#gg g g dgg}d-d.l m} |D ]R\}}|jj|j|}||krtd/| d0 td1|  td2|  qd3S )4ug   
        Тестирование
        Запуск: models.CmfTask.dp._test_query_params()
        r   r  Zcache_status_typer   ZIN_PROGRESSZlogic_prefixzlist.agile_sprintZCmfListzCmfList.cache_status_typezCmfList.logic_prefixzCmfTask.listsr   r   {   r:   ZqwezCmfTask.namezcmf_owner.idzCmfPerson:12312321Z	CmfPersonzCmfPerson.idzCmfTask.cmf_ownerzCmfTask.cache_status_typezCmfTask.logic_prefixZext_idZLIKEz
%::qwe::%%zCmfTask.ext_idz::qwe::zparent.ext_idzCmfTask.parentzstatus.ext_idZ	CmfStatuszCmfStatus.ext_idzCmfTask.statuszstatus.status_code_idZ12345zCmfStatus.status_codezstatus.status_coder   Z	qweqweqwez
CmfTask.idzparent.root_parent.namestatusr   rX   uC   Ошибка в результате _query_params(models.CmfTask, r   u   Факт:        u   Должно быть: N)rZ   rY   ZCmfTaskZdpr   r@   )r   Zf_listrY   fZres_origr   r   r   r   _test_query_params;  sf    








@
zDataProvider._test_query_paramsc          
      O   sZ  |rt d| jjp|}t  | | j||d< tjjj| jj	 df||}|sd|sdtjj
 rjd}ntjj|}|dkrtjtjjjd|  g S |dk	rtjtjjjd|  |S tjtjjjd|  | jj| jf|d	|i|}| jjd
kr|S |sR| | j|d |d|d}	tjjj||| jj	 |	d |S dS )u   
        Пробросили сюда relation_load и relation_load_only для реализации join и подселектов в будущем
        :param args:
        :param kwargs:
        :return:
        r   r   z.listNr   zlist() From cache  Empty zlist() From cache zDP: list() From NOcache r   r   r   r   r   )r;   rb   r   r   r   r   r   r   r   r,   r   r6   r   r   r   r!   r:   r   r   )
r   r   r   r   rc   r   r   r   r   r   r   r   r   r!     s.     "zDataProvider.list)r   r   c          	      O   s*  |rt d| jjp|}t  | | j||d< tjjj| jj	 df||}|s`tjj
 rfd }ntjj|}|dkrtjtjjjd|  tdn|d k	rtjtjjjd|  |S t  | jj| jf||}|s&| | j|d |d|d	}tjjj||| jj	 |d
 |S )Nr   r   z.countr   zcount() From cache Empty z$BUG: count() cache can not be empty!zcount() From cache r   r   r   )r;   rb   r   r   r   r   r   r   r   r,   r   r6   r   r   rH   r   ri   r   r   )	r   r   r   rc   r   r   r   r   r   r   r   r   ri     s*     
"zDataProvider.count)r   c                O   s   t | jj||| j| j|dS N)rP   rb   r   )
QueryProxyr   queryrb   )r   r   rc   r   r   r   r   ro     s       zDataProvider.query_deprecated)NN)NNr   )r,   r-   r.   rr   recompileZTABLE_FIELD_REr`   propertyr   r6   rf   rh   rU   rT   rg   r   r   r
  r!   ri   ro   r   r   r   r   r     s"   


&5
|O%r   c                   @   sf   e Zd ZdZdddZdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zedd Zdd ZdS )r  u   
    Оборачиваем кастомный запрос и добавляем возможность извлекать данные с автомаппингом.
    TODO: Проверить слайсы query[a:b]
    Nc                 C   s0   || _ || _|| _t|t | _t|| _d S r   )_queryr   rb   r    rs   _mapper_is_myr   _mapper)r   r  rP   rb   r   r   r   r   r`     s
    zQueryProxy.__init__c                    s    fdd}|S )u   Обёртка для методов, которые возвращают новый запрос на основании текущего.c                     s(   t j | |}t|jjjdS r  )rL   r  r  r   rb   r  )rc   r   Z	new_queryitemr   r   r   method_proxy  s    z,QueryProxy.__getattr__.<locals>.method_proxyr   )r   r  r  r   r  r   __getattr__  s    zQueryProxy.__getattr__c                 C   s2   | j r.| j |r.| jj|| j t|d}|S )u6   Автоконвертация объектов в CMF)rb   )r   rm   r  ry   rk   r   )r   r   r   r   r   
_map_value  s    zQueryProxy._map_valuec                    s.   t |tr t fdd|D S  |S d S )Nc                 3   s   | ]}  |V  qd S r   )r  )r   colrj   r   r   	<genexpr>  s     z&QueryProxy._map_row.<locals>.<genexpr>)r    tupler  )r   rowr   rj   r   _map_row  s    
zQueryProxy._map_rowc                    s   t  j}tjjd| }tjj r.d}ntjj|}t  |dkrhtj	tjjj
d|  g S |dk	rtj	tjjj
d|  |S tj	tjjj
d|   fdd jD }tjj|| jj   jr j  |S dS )	uo   Метод извлечения всех данных из текущего запрос с маппингом.Z
custom_allNr   zall() From cache Empty zall() From cache zDP: all() From NOcache c                    s   g | ]}  |qS r   )r  )r   r  rj   r   r   r     s     z"QueryProxy.all.<locals>.<listcomp>)r4   r  r   r   r   r   r   r6   r   r   r   r   rb   r,   r  r  rt   r   sqlr   r   r   r   rj   r   all  s$    

zQueryProxy.allc                 C   s   t | j}tjjd| }tjj r.d}ntjj|}t  |dkrhtj	tjjj
d|  dS |dk	rtj	tjjj
d|  |S tj	tjjj
d|  | j }| |}tjj||| jj  | jr| j  |S dS )uP   Метод извлечения первой строки с маппингом.Zcustom_firstNr   zDP: first() From cache Empty zDP: first() From cache zDP: first() From NOcache )r4   r  r   r   r   r   r   r6   r   r   r   firstr  r   rb   r,   r  r  rt   )r   r  r   r   r  r   r   r   r   r!    s&    



zQueryProxy.firstc                 C   s   t   t| j}tjjd| }tjj r4d }ntjj|}t   |dkrntj	tjjj
d|  d S |d k	rtj	tjjj
d|  |S tj	tjjj
d | j }tjj||| jj  |S )NZcustom_countr   zDP: count() From cache Empty zDP: count() From cache zDP: count() From NOcache TODO)r   r4   r  r   r   r   r   r   r6   r   r   ri   r   rb   r,   r  r   r   r   ri     s"    

zQueryProxy.countc                 O   s   | j j||}|S r   )r  rg   )r   rc   r   r   r   r   r   rg   2  s    zQueryProxy.deletec                 C   s   | j S r   )r  rj   r   r   r   dd_query7  s    zQueryProxy.dd_queryc                 C   s   t |  S )u+   Чтение строк из запроса)iterr   rj   r   r   r   __iter__;  s    zQueryProxy.__iter__)NNN)r,   r-   r.   rr   r`   r  r  r  r   r!  ri   rg   r  r"  r$  r   r   r   r   r    s   

r  )N)N)N)r   )(r   rJ   r   r   r  collectionsr   r   r   r   typingr   r   Zflaskr   Zcmf.appr   r   rZ   r   Zmodels.base_modelr
   r5   r4   r8   r?   rA   r=   rN   rQ   rV   rW   r[   r\   rs   r   r   r   r   r  r   r   r   r   <module>   sF   
+

<7v 	
   4