a
    4be                     @   s   d 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 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 ddlmZ G dd deZG dd deZG dd deZG dd deZdS )zDescriptor properties are more "auxiliary" properties
that exist as configurational elements, but don't participate
as actively in the load/persist ORM loop.

   )
attributes)util)MapperProperty)PropComparator)	_none_set   )event)exc)schema)sql
expression)	operatorsc                   @   s$   e Zd ZdZdZdZdZdd ZdS )DescriptorPropertyzO:class:`.MapperProperty` which proxies access to a
    user-defined descriptor.NFc                    s   G fdddt }jd u rFt jjd } j|rF|_jd u rfdd}fdd}fdd}t|||d	_tjj	jjj fd
dj
d}|j|_ jj| d S )Nc                       sL   e Zd ZdZdZdZe fddZdd Ze	 drHe
jf fdd		Zd
S )z7DescriptorProperty.instrument_class.<locals>._ProxyImplFTc                    s    j S N)uses_objectsselfprop >lib/python3.9/site-packages/sqlalchemy/orm/descriptor_props.pyr   -   s    zDDescriptorProperty.instrument_class.<locals>._ProxyImpl.uses_objectsc                 S   s
   || _ d S r   key)r   r   r   r   r   __init__1   s    z@DescriptorProperty.instrument_class.<locals>._ProxyImpl.__init__get_historyc                    s     |||S r   )r   )r   statedict_passiver   r   r   r   6   s    zCDescriptorProperty.instrument_class.<locals>._ProxyImpl.get_historyN)__name__
__module____qualname__Zaccepts_scalar_loaderZload_on_unexpireZ
collectionpropertyr   r   hasattrr   PASSIVE_OFFr   r   r   r   r   
_ProxyImpl(   s   
r%   c                    s   t |  j| d S r   )setattrname)objvaluer   r   r   fsetB   s    z1DescriptorProperty.instrument_class.<locals>.fsetc                    s   t |  j d S r   )delattrr'   r(   r   r   r   fdelE   s    z1DescriptorProperty.instrument_class.<locals>.fdelc                    s   t |  jS r   )getattrr'   r,   r   r   r   fgetH   s    z1DescriptorProperty.instrument_class.<locals>.fget)r/   r*   r-   c                      s
     S r   )_comparator_factoryr   )mapperr   r   r   <lambda>Q       z5DescriptorProperty.instrument_class.<locals>.<lambda>)docZoriginal_property)object
descriptorr.   class_r   Z_is_userland_descriptorr"   r   Zcreate_proxied_attributeparentr4   implZclass_managerZinstrument_attribute)r   r1   r%   Zdescr*   r-   r/   Z
proxy_attrr   )r1   r   r   r   instrument_class%   s*    


z#DescriptorProperty.instrument_class)r   r    r!   __doc__r4   r   Z_links_to_entityr:   r   r   r   r   r      s
   r   c                       s   e Zd ZdZ fddZ fddZdd Ze Zdd	 Z	e
jd
d Ze
jdd Zedd Zdd Zdd Ze
jdd ZejfddZdd ZG dd dejZG dd deZdd Z  ZS ) CompositePropertyzDefines a "composite" mapped attribute, representing a collection
    of columns as one attribute.

    :class:`.CompositeProperty` is constructed using the :func:`.composite`
    function.

    .. seealso::

        :ref:`mapper_composite`

    c                    s   t t|   || _|| _|dd| _|dd| _|dd| _|	d| j
j| _d|v rj|	d| _t|  |   dS )a`  Return a composite column-based property for use with a Mapper.

        See the mapping documentation section :ref:`mapper_composite` for a
        full usage example.

        The :class:`.MapperProperty` returned by :func:`.composite`
        is the :class:`.CompositeProperty`.

        :param class\_:
          The "composite type" class, or any classmethod or callable which
          will produce a new instance of the composite object given the
          column values in order.

        :param \*cols:
          List of Column objects to be mapped.

        :param active_history=False:
          When ``True``, indicates that the "previous" value for a
          scalar attribute should be loaded when replaced, if not
          already loaded.  See the same flag on :func:`.column_property`.

        :param group:
          A group name for this property when marked as deferred.

        :param deferred:
          When True, the column property is "deferred", meaning that it does
          not load immediately, and is instead loaded when the attribute is
          first accessed on an instance.  See also
          :func:`~sqlalchemy.orm.deferred`.

        :param comparator_factory:  a class which extends
          :class:`.CompositeProperty.Comparator` which provides custom SQL
          clause generation for comparison operations.

        :param doc:
          optional string that will be applied as the doc on the
          class-bound descriptor.

        :param info: Optional data dictionary which will be populated into the
            :attr:`.MapperProperty.info` attribute of this object.

        active_historyFdeferredgroupNcomparator_factoryinfo)superr<   r   attrscomposite_classgetr=   r>   r?   pop	__class__
Comparatorr@   rA   r   set_creation_order_create_descriptor)r   r7   rC   kwargsrG   r   r   r   f   s    +
zCompositeProperty.__init__c                    s   t t| | |   d S r   )rB   r<   r:   _setup_event_handlersr   r1   rL   r   r   r:      s    z"CompositeProperty.instrument_classc                 C   s   |    dS )zInitialization which occurs after the :class:`.CompositeProperty`
        has been associated with its parent mapper.

        N)_setup_arguments_on_columnsr   r   r   r   do_init   s    zCompositeProperty.do_initc                    s6    fdd} fdd} fdd}t ||| _dS )ztCreate the Python descriptor that will serve as
        the access point on instances of the mapped class.

        c                    s   t  }t  }j|vrx fddjD }j|vrx|jd usPt|sxj| |j< |jj	
|jjg |jd S )Nc                    s   g | ]}t  |qS r   )r.   .0r   instancer   r   
<listcomp>   s   zFCompositeProperty._create_descriptor.<locals>.fget.<locals>.<listcomp>)r   instance_dictinstance_stater   _attribute_keysr   
issupersetrD   managerdispatchrefresh_COMPOSITE_FGETrE   )rT   r   r   valuesr   rS   r   r/      s     



	
z2CompositeProperty._create_descriptor.<locals>.fgetc                    s   t | }t | }|j j }| jt j}|jjD ]}|||||j	}q8|| j< |d u rz j
D ]}t| |d  qfn&t j
| D ]\}}t| || qd S r   )r   rV   rW   rZ   r   rE   NO_VALUEr[   setr9   rX   r&   zip__composite_values__)rT   r)   r   r   attrpreviousfnr   r   r   r   r*      s    




z2CompositeProperty._create_descriptor.<locals>.fsetc                    s^   t | }t | }| jt j}|j j }|j|||j	  j
D ]}t| |d  qHd S r   )r   rW   rV   rF   r   r_   rZ   r[   remover9   rX   r&   )rT   r   r   rd   rc   r   r   r   r   r-      s    


z2CompositeProperty._create_descriptor.<locals>.fdelN)r"   r6   )r   r/   r*   r-   r   r   r   rJ      s    	z$CompositeProperty._create_descriptorc                    s    fdd j D S )Nc                    s   g | ]}t  jj|jqS r   )r.   r8   r7   r   rR   r   r   r   r   rU      r3   z:CompositeProperty._comparable_elements.<locals>.<listcomp>propsr   r   r   r   _comparable_elements   s    z&CompositeProperty._comparable_elementsc                 C   sx   g }| j D ]h}t|tr*| jj|dd}n>t|tjrD| jj| }n$t|tj	rX|j
}ntd|f || q
|S )NF)Z_configure_mappersz[Composite expects Column objects or mapped attributes/attribute names as arguments, got: %r)rC   
isinstancestrr8   Zget_propertyr
   Column_columntopropertyr   ZInstrumentedAttributer"   sa_excArgumentErrorappend)r   ri   rc   r   r   r   r   ri      s    

zCompositeProperty.propsc                 C   s   dd | j D S )Nc                 S   s   g | ]}t |tjr|qS r   )rk   r
   rm   )rR   ar   r   r   rU     r3   z-CompositeProperty.columns.<locals>.<listcomp>)rC   r   r   r   r   columns  s    zCompositeProperty.columnsc                 C   s4   | j D ](}| j|_| jr&| j|_d|_| j|_qdS )zwPropagate configuration arguments made on this composite
        to the target columns, for those that apply.

        ))r>   T)Z
instrumentTN)ri   r=   r>   Zstrategy_keyr?   )r   r   r   r   r   rO     s    
z-CompositeProperty._setup_arguments_on_columnsc                    s    fdd} fdd}fdd fdd}fd	d
}t jjd|dd t jjd|dd t jjd|ddd t jjd|ddd t jjd|ddd dS )z>Establish events that populate/expire the composite attribute.c                    s    | |d dd d S )NF
is_refreshr   )r   context)_load_refresh_handlerr   r   load_handler  s    z=CompositeProperty._setup_event_handlers.<locals>.load_handlerc                    s.   |rj hj|r* | ||dd d S )NTrt   )r   unionrX   intersection)r   rv   to_loadrw   r   r   r   refresh_handler  s    z@CompositeProperty._setup_event_handlers.<locals>.refresh_handlerc                    s`    j }|r|ju r"j|v r"d S jD ]}||vr( d S q(j fddjD  |j< d S )Nc                    s   g | ]} j | qS r   )dictrQ   r   r   r   rU   9  r3   zZCompositeProperty._setup_event_handlers.<locals>._load_refresh_handler.<locals>.<listcomp>)r~   r]   r   rX   rD   )r   rv   r{   ru   r   kr   r   r   rw      s    
zFCompositeProperty._setup_event_handlers.<locals>._load_refresh_handlerc                    s,   |d u st  j|r(| j jd  d S r   )r`   rX   rz   r~   rF   r   )r   keysr   r   r   expire_handler<  s    z?CompositeProperty._setup_event_handlers.<locals>.expire_handlerc                    s   |j  jd dS )zAfter an insert or update, some columns may be expired due
            to server side defaults, or re-populated due to client side
            defaults.  Pop out the composite value here so that it
            recreates.

            N)r~   rF   r   )r1   Z
connectionr   r   r   r   insert_update_handler@  s    zFCompositeProperty._setup_event_handlers.<locals>.insert_update_handlerZafter_insertT)rawZafter_updateload)r   Z	propagater\   ZexpireN)r   Zlistenr8   )r   rx   r}   r   r   r   r|   r   rM     s(    


z'CompositeProperty._setup_event_handlersc                 C   s   dd | j D S )Nc                 S   s   g | ]
}|j qS r   r   rg   r   r   r   rU   ^  r3   z5CompositeProperty._attribute_keys.<locals>.<listcomp>rh   r   r   r   r   rX   \  s    z!CompositeProperty._attribute_keysc                 C   s   g }g }d}| j D ]j}|j}|j| j||}	|	 r<d}|	 }
|
rT||
 n
|d |	j	rr||	j	 q|d q|rt
| j| gd| j| gS t
d| j| gdS dS )z>Provided for userland code that uses attributes.get_history().FTNr   )ri   r   rZ   r9   r   Zhas_changesnon_deletedextendrq   deletedr   ZHistoryrD   )r   r   r   r   Zaddedr   Zhas_historyr   r   Zhistr   r   r   r   r   `  s,    



zCompositeProperty.get_historyc                 C   s   |  | |S r   )r@   rN   r   r   r   r0     s    z%CompositeProperty._comparator_factoryc                       s$   e Zd Z fddZdd Z  ZS )z!CompositeProperty.CompositeBundlec                    s&   || _ ttj| j|jg|R   d S r   )r"   rB   r<   CompositeBundler   r   )r   Z	property_exprrL   r   r   r     s    z*CompositeProperty.CompositeBundle.__init__c                    s    fdd}|S )Nc                    s   j j fddD  S )Nc                    s   g | ]}| qS r   r   )rR   procrowr   r   rU     r3   zXCompositeProperty.CompositeBundle.create_row_processor.<locals>.proc.<locals>.<listcomp>)r"   rD   r   procsr   r   r   r     s    zDCompositeProperty.CompositeBundle.create_row_processor.<locals>.procr   )r   Zqueryr   labelsr   r   r   r   create_row_processor  s    z6CompositeProperty.CompositeBundle.create_row_processor)r   r    r!   r   r   __classcell__r   r   rL   r   r     s   r   c                   @   s^   e Zd ZdZdZejdd Zdd Zejdd Z	d	d
 Z
ejdd Zdd Zdd ZdS )zCompositeProperty.Comparatora  Produce boolean, comparison, and other operators for
        :class:`.CompositeProperty` attributes.

        See the example in :ref:`composite_operations` for an overview
        of usage , as well as the documentation for :class:`.PropComparator`.

        .. seealso::

            :class:`.PropComparator`

            :class:`.ColumnOperators`

            :ref:`types_operators`

            :attr:`.TypeEngine.comparator_factory`

        Nc                 C   s   t j| jddiS )Nr?   F)r   Z
ClauseListrj   r   r   r   r   clauses  s
    z$CompositeProperty.Comparator.clausesc                 C   s   | j S r   r   r   r   r   r   __clause_element__  s    z/CompositeProperty.Comparator.__clause_element__c                 C   s*   | j | j| j| jjd}t| j|S )N)ZparententityZparentmapperZ	proxy_key)r   Z	_annotateZ_parententityr   r   r<   r   )r   r   r   r   r   r     s    z'CompositeProperty.Comparator.expressionc                 C   sh   t |tjjr|j}|d u r0dd | jjD }n,t || jjrH| }nt	
d| j|f t| j|S )Nc                 S   s   g | ]}d qS r   r   rQ   r   r   r   rU     r3   zDCompositeProperty.Comparator._bulk_update_tuples.<locals>.<listcomp>z)Can't UPDATE composite attribute %s to %r)rk   r   elementsZBindParameterr)   r   rX   rD   rb   ro   rp   ra   rj   )r   r)   r^   r   r   r   _bulk_update_tuples  s    
z0CompositeProperty.Comparator._bulk_update_tuplesc                    s(    j r fdd jjD S  jjS d S )Nc                    s   g | ]}t  jj|jqS r   )r.   _adapt_to_entityZentityr   rg   r   r   r   rU     s   zECompositeProperty.Comparator._comparable_elements.<locals>.<listcomp>)r   r   rj   r   r   r   r   rj     s
    
z1CompositeProperty.Comparator._comparable_elementsc                    s^   |d u rd gt  jj }n| }dd t jj|D } jrT fdd|D }tj| S )Nc                 S   s   g | ]\}}||kqS r   r   )rR   rr   br   r   r   rU     s   z7CompositeProperty.Comparator.__eq__.<locals>.<listcomp>c                    s   g | ]}  |qS r   )Zadapter)rR   xr   r   r   rU     r3   )lenr   rj   rb   ra   r   r   and_)r   otherr^   Zcomparisonsr   r   r   __eq__  s    z#CompositeProperty.Comparator.__eq__c                 C   s   t | |S r   )r   not_r   )r   r   r   r   r   __ne__  s    z#CompositeProperty.Comparator.__ne__)r   r    r!   r;   __hash__r   memoized_propertyr   r   r   r   rj   r   r   r   r   r   r   rH     s   



	rH   c                 C   s   t | jjjd | j S )N.)rl   r8   r7   r   r   r   r   r   r   __str__  s    zCompositeProperty.__str__)r   r    r!   r;   r   r:   rP   r5   r]   rJ   r   r   rj   ri   r"   rs   rO   rM   rX   r   r$   r   r0   orm_utilZBundler   r   rH   r   r   r   r   rL   r   r<   Y   s*   ;=


J
 Rr<   c                       s(   e Zd ZdZdd Z fddZ  ZS )ConcreteInheritedPropertya4  A 'do nothing' :class:`.MapperProperty` that disables
    an attribute on a concrete subclass that is only present
    on the inherited mapper, not the concrete classes' mapper.

    Cases where this occurs include:

    * When the superclass mapper is mapped against a
      "polymorphic union", which includes all attributes from
      all subclasses.
    * When a relationship() is configured on an inherited mapper,
      but not on the subclass mapper.  Concrete mappers require
      that relationship() is configured explicitly on each
      subclass.

    c                 C   s8   d }| j  D ]$}|j| j }t|ts|j} q4q|S r   )r8   Ziterate_to_rootZ_propsr   rk   r   r@   )r   r1   Zcomparator_callablempr   r   r   r0     s    
z-ConcreteInheritedProperty._comparator_factoryc                    s<   t t    fddG  fdddt}|  _d S )Nc                      s   t d j j jf d S )NzgConcrete %s does not implement attribute %r at the instance level.  Add this property explicitly to %s.)AttributeErrorr8   r   r   r   r   r   warn  s
    z0ConcreteInheritedProperty.__init__.<locals>.warnc                       s2   e Zd ZfddZfddZ fddZdS )zDConcreteInheritedProperty.__init__.<locals>.NoninheritedConcretePropc                    s
      d S r   r   )sr(   r)   r   r   r   __set__  s    zLConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__set__c                    s
      d S r   r   )r   r(   r   r   r   
__delete__  s    zOConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__delete__c                    s   |d u r j S   d S r   )r6   )r   r(   ownerr   r   r   r   __get__  s    zLConcreteInheritedProperty.__init__.<locals>.NoninheritedConcreteProp.__get__N)r   r    r!   r   r   r   r   r   r   r   NoninheritedConcreteProp  s   r   )rB   r   r   r5   r6   )r   r   rL   r   r   r     s    z"ConcreteInheritedProperty.__init__)r   r    r!   r;   r0   r   r   r   r   rL   r   r     s   
r   c                       sZ   e Zd Zd fdd	Zedd Zejdd Zdd	 Z	d
d Z
eddd Z  ZS )SynonymPropertyNc                    sR   t t|   || _|| _|| _|| _|p6|r4|jp6d| _|rD|| _	t
|  dS )a  Denote an attribute name as a synonym to a mapped property,
        in that the attribute will mirror the value and expression behavior
        of another attribute.

        e.g.::

            class MyClass(Base):
                __tablename__ = 'my_table'

                id = Column(Integer, primary_key=True)
                job_status = Column(String(50))

                status = synonym("job_status")


        :param name: the name of the existing mapped property.  This
          can refer to the string name ORM-mapped attribute
          configured on the class, including column-bound attributes
          and relationships.

        :param descriptor: a Python :term:`descriptor` that will be used
          as a getter (and potentially a setter) when this attribute is
          accessed at the instance level.

        :param map_column: **For classical mappings and mappings against
          an existing Table object only**.  if ``True``, the :func:`.synonym`
          construct will locate the :class:`_schema.Column`
          object upon the mapped
          table that would normally be associated with the attribute name of
          this synonym, and produce a new :class:`.ColumnProperty` that instead
          maps this :class:`_schema.Column`
          to the alternate name given as the "name"
          argument of the synonym; in this way, the usual step of redefining
          the mapping of the :class:`_schema.Column`
          to be under a different name is
          unnecessary. This is usually intended to be used when a
          :class:`_schema.Column`
          is to be replaced with an attribute that also uses a
          descriptor, that is, in conjunction with the
          :paramref:`.synonym.descriptor` parameter::

            my_table = Table(
                "my_table", metadata,
                Column('id', Integer, primary_key=True),
                Column('job_status', String(50))
            )

            class MyClass(object):
                @property
                def _job_status_descriptor(self):
                    return "Status: %s" % self._job_status


            mapper(
                MyClass, my_table, properties={
                    "job_status": synonym(
                        "_job_status", map_column=True,
                        descriptor=MyClass._job_status_descriptor)
                }
            )

          Above, the attribute named ``_job_status`` is automatically
          mapped to the ``job_status`` column::

            >>> j1 = MyClass()
            >>> j1._job_status = "employed"
            >>> j1.job_status
            Status: employed

          When using Declarative, in order to provide a descriptor in
          conjunction with a synonym, use the
          :func:`sqlalchemy.ext.declarative.synonym_for` helper.  However,
          note that the :ref:`hybrid properties <mapper_hybrids>` feature
          should usually be preferred, particularly when redefining attribute
          behavior.

        :param info: Optional data dictionary which will be populated into the
            :attr:`.InspectionAttr.info` attribute of this object.

            .. versionadded:: 1.0.0

        :param comparator_factory: A subclass of :class:`.PropComparator`
          that will provide custom comparison behavior at the SQL expression
          level.

          .. note::

            For the use case of providing an attribute which redefines both
            Python-level and SQL-expression level behavior of an attribute,
            please refer to the Hybrid attribute introduced at
            :ref:`mapper_hybrids` for a more effective technique.

        .. seealso::

            :ref:`synonyms` - Overview of synonyms

            :func:`.synonym_for` - a helper oriented towards Declarative

            :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
            updated approach to augmenting attribute behavior more flexibly
            than can be achieved with synonyms.

        N)rB   r   r   r'   
map_columnr6   r@   r;   r4   rA   r   rI   )r   r'   r   r6   r@   r4   rA   rL   r   r   r     s    pzSynonymProperty.__init__c                 C   s   t | jj| jjjS r   )r.   r8   r7   r'   r9   r   r   r   r   r   r     s    zSynonymProperty.uses_objectsc                 C   sj   t | jj| j}t|dr&t|jtsdt|tj	r8|j
S t|tjrH|S td| jjj| j|f |jS )Nr"   zGsynonym() attribute "%s.%s" only supports ORM mapped attributes, got %r)r.   r8   r7   r'   r#   rk   r"   r   r   ZQueryableAttributeZ
comparatorr   ZColumnOperatorsro   ZInvalidRequestErrorr   )r   rc   r   r   r   _proxied_object  s    zSynonymProperty._proxied_objectc                 C   s<   | j }t|tr4| jr$| ||}n|||}|S |S d S r   )r   rk   r   r@   )r   r1   r   compr   r   r   r0     s    
z#SynonymProperty._comparator_factoryc                 O   s"   t | jj| j}|jj|i |S r   )r.   r8   r7   r'   r9   r   )r   argkwrc   r   r   r   r     s    zSynonymProperty.get_historyzsqlalchemy.orm.propertiesc                 C   s   t jj}| jr| j|jjvr:td| j	|jj
| jf nN|jj| j |jv r|j|jj| j  j| j	krtd| j| j	| j	| jf ||jj| j }|j| j	||dd | j|_|| _d S )Nz>Can't compile synonym '%s': no column on table '%s' named '%s'zpCan't call map_column=True for synonym %r=%r, a ColumnProperty already exists keyed to the name %r for column %rT)initZ	setparent)r   Z	preloadedZorm_propertiesr   r   Zpersist_selectablecro   rp   r'   Zdescriptionrn   ZColumnPropertyZ_configure_propertyZ_mapped_by_synonymr8   )r   r8   r   Z
propertiesr   r   r   r   
set_parent  s@    
zSynonymProperty.set_parent)NNNNN)r   r    r!   r   r"   r   r   r   r   r0   r   Zpreload_moduler   r   r   r   rL   r   r     s        |

r   N)r;    r   r   r   Z
interfacesr   r   r   r   r	   ro   r
   r   r   r   r   r<   r   r   r   r   r   r   <module>   s&   =   5