U
    W+d@9                     @   s0   d dl mZ G dd deZG dd deZdS )    )deepcopyc                   @   s   e Zd ZdS )NEWVALUEN)__name__
__module____qualname__ r   r   8/tmp/pip-unpacked-wheel-dlxw5sjy/boto/dynamodb2/items.pyr      s   r   c                   @   s   e Zd ZdZd6ddZdd Zdd	 Zd
d Zdd Zdd Z	dd Z
d7ddZdd Zdd Zdd ZeZdd Zd8ddZdd Zd d! Zd"d# Zd$d% Zd&d' Zd9d(d)Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd:d2d3Zd4d5 ZdS );Itema  
    An object representing the item data within a DynamoDB table.

    An item is largely schema-free, meaning it can contain any data. The only
    limitation is that it must have data for the fields in the ``Table``'s
    schema.

    This object presents a dictionary-like interface for accessing/storing
    data. It also tries to intelligently track how data has changed throughout
    the life of the instance, to be as efficient as possible about updates.

    Empty items, or items that have no data, are considered falsey.

    NFc                 C   s\   || _ || _i | _|| _|j| _t| jtr6| jj| _| jdkrFi | _| jrXt| j| _dS )a  
        Constructs an (unsaved) ``Item`` instance.

        To persist the data in DynamoDB, you'll need to call the ``Item.save``
        (or ``Item.partial_save``) on the instance.

        Requires a ``table`` parameter, which should be a ``Table`` instance.
        This is required, as DynamoDB's API is focus around all operations
        being table-level. It's also for persisting schema around many objects.

        Optionally accepts a ``data`` parameter, which should be a dictionary
        of the fields & values of the item. Alternatively, an ``Item`` instance
        may be provided from which to extract the data.

        Optionally accepts a ``loaded`` parameter, which should be a boolean.
        ``True`` if it was preexisting data loaded from DynamoDB, ``False`` if
        it's new data from the user. Default is ``False``.

        Example::

            >>> users = Table('users')
            >>> user = Item(users, data={
            ...     'username': 'johndoe',
            ...     'first_name': 'John',
            ...     'date_joined': 1248o61592,
            ... })

            # Change existing data.
            >>> user['first_name'] = 'Johann'
            # Add more data.
            >>> user['last_name'] = 'Doe'
            # Delete data.
            >>> del user['date_joined']

            # Iterate over all the data.
            >>> for field, val in user.items():
            ...     print "%s: %s" % (field, val)
            username: johndoe
            first_name: John
            date_joined: 1248o61592

        N)table_loaded
_orig_data_data
_dynamizer
isinstancer	   r   )selfr
   dataZloadedr   r   r   __init__   s    +

zItem.__init__c                 C   s   | j |d S Nr   getr   keyr   r   r   __getitem__Q   s    zItem.__getitem__c                 C   s   || j |< d S r   r   )r   r   valuer   r   r   __setitem__T   s    zItem.__setitem__c                 C   s   || j krd S | j |= d S r   r   r   r   r   r   __delitem__W   s    
zItem.__delitem__c                 C   s
   | j  S r   )r   keysr   r   r   r   r   ]   s    z	Item.keysc                 C   s
   | j  S r   )r   valuesr   r   r   r   r   `   s    zItem.valuesc                 C   s
   | j  S r   )r   itemsr   r   r   r   r    c   s    z
Item.itemsc                 C   s   | j ||S r   r   )r   r   defaultr   r   r   r   f   s    zItem.getc                 c   s   | j D ]}| j | V  qd S r   r   r   r   r   r   __iter__i   s    
zItem.__iter__c                 C   s
   || j kS r   r   r   r   r   r   __contains__m   s    zItem.__contains__c                 C   s
   t | jS r   )boolr   r   r   r   r   __bool__p   s    zItem.__bool__c                 C   s   i i g d}t | j }t | j }||D ]J}| j| | j| kr2| | j| rn| j| |d |< q2|d | q2||D ]&}| | j| r| j| |d |< q||D ]}|d | q|S )z
        Checks the ``-orig_data`` against the ``_data`` to determine what
        changes to the data are present.

        Returns a dictionary containing the keys ``adds``, ``changes`` &
        ``deletes``, containing the updated data.
        addschangesdeletesr(   r)   r'   )setr   r   r   intersection_is_storableappend
difference)r   alterations	orig_keysZ	data_keysr   r   r   r   _determine_alterationsu   s"    	zItem._determine_alterationsc                 C   s6   |dkr|   }d}dD ]}t|| rd} q2q|S )a  
        Returns whether or not the data has changed on the ``Item``.

        Optionally accepts a ``data`` argument, which accepts the output from
        ``self._determine_alterations()`` if you've already called it. Typically
        unnecessary to do. Default is ``None``.

        Example:

            >>> user.needs_save()
            False
            >>> user['first_name'] = 'Johann'
            >>> user.needs_save()
            True

        NFr&   T)r1   len)r   r   
needs_savekindr   r   r   r3      s    zItem.needs_savec                 C   s   t | j| _dS )aM  
        Marks an ``Item`` instance as no longer needing to be saved.

        Example:

            >>> user.needs_save()
            False
            >>> user['first_name'] = 'Johann'
            >>> user.needs_save()
            True
            >>> user.mark_clean()
            >>> user.needs_save()
            False

        N)r   r   r   r   r   r   r   
mark_clean   s    zItem.mark_cleanc                 C   s   dS )z
        DEPRECATED: Marks an ``Item`` instance as needing to be saved.

        This method is no longer necessary, as the state tracking on ``Item``
        has been improved to automatically detect proper state.
        Nr   r   r   r   r   
mark_dirty   s    zItem.mark_dirtyc                 C   sF   i | _ |di  D ]\}}| j|| |< qd| _t| j | _dS )aF  
        This is only useful when being handed raw data from DynamoDB directly.
        If you have a Python datastructure already, use the ``__init__`` or
        manually set the data instead.

        Largely internal, unless you know what you're doing or are trying to
        mix the low-level & high-level APIs.
        r	   TN)r   r   r    r   decoder   r   r   )r   r   
field_nameZfield_valuer   r   r   load   s
    	z	Item.loadc                 C   s(   | j  }i }|D ]}| | ||< q|S )z\
        Returns a Python-style dict of the keys/values.

        Largely internal.
        )r
   Zget_key_fields)r   Z
key_fieldskey_datar   r   r   r   get_keys   s
    
zItem.get_keysc                 C   s.   i }|    D ]\}}| j|||< q|S )z^
        Returns a DynamoDB-style dict of the keys/values.

        Largely internal.
        )r;   r    r   encode)r   Zraw_key_datar   r   r   r   r   get_raw_keys   s    zItem.get_raw_keysc                 C   s   i }|dkr(t | j t | j  }t|}|D ]}ddi||< d}|| jkrh|| jkrhtd| | j|t}| j|t}||kr|}n,|| jkr|| jkrd|| d< q|}n|}|dk	r4| j	||| d< q4|S )zm
        Builds up a list of expecations to hand off to DynamoDB on save.

        Largely internal.
        NZExistsTzUnknown key %s provided.FValue)
listr   r   r   r*   
ValueErrorr   r   r   r<   )r   fieldsexpectsr   r   Z
orig_valueZcurrent_valuer   r   r   build_expects   s.     

zItem.build_expectsc                 C   s   |s|dkrdS dS )N)r   g        FFTr   )r   r   r   r   r   r,   1  s    zItem._is_storablec                 C   s8   i }| j  D ]$\}}| |s"q| j|||< q|S )z
        Runs through all fields & encodes them to be handed off to DynamoDB
        as part of an ``save`` (``put_item``) call.

        Largely internal.
        )r   r    r,   r   r<   )r   
final_datar   r   r   r   r   prepare_full:  s    	
zItem.prepare_fullc                 C   s   i }t  }|  }|d  D ].\}}d| j| j| d||< || q|d  D ].\}}d| j| j| d||< || qZ|d D ]}ddi||< || q||fS )z
        Runs through **ONLY** the changed/deleted fields & encodes them to be
        handed off to DynamoDB as part of an ``partial_save`` (``update_item``)
        call.

        Largely internal.
        r'   PUT)Actionr>   r(   r)   rG   DELETE)r*   r1   r    r   r<   r   add)r   rD   rA   r/   r   r   r   r   r   prepare_partialM  s&    


 zItem.prepare_partialc              	   C   s   |   }|  \}}|sdS | D ]:\}}||kr$||= z|| W q$ tk
r\   Y q$X q$| j|d}| jj|||d}|   |S )an  
        Saves only the changed data to DynamoDB.

        Extremely useful for high-volume/high-write data sets, this allows
        you to update only a handful of fields rather than having to push
        entire items. This prevents many accidental overwrite situations as
        well as saves on the amount of data to transfer over the wire.

        Returns ``True`` on success, ``False`` if no save was performed or
        the write failed.

        Example::

            >>> user['last_name'] = 'Doh!'
            # Only the last name field will be sent to DynamoDB.
            >>> user.partial_save()

        F)rA   rB   )	r;   rJ   r    removeKeyErrorrC   r
   Z_update_itemr5   )r   r   rD   rA   	fieldnamer   rB   returnedr   r   r   partial_saveq  s    zItem.partial_savec                 C   sH   |   s|sdS |  }d}|dkr,|  }| jj||d}|   |S )aU  
        Saves all data to DynamoDB.

        By default, this attempts to ensure that none of the underlying
        data has changed. If any fields have changed in between when the
        ``Item`` was constructed & when it is saved, this call will fail so
        as not to cause any data loss.

        If you're sure possibly overwriting data is acceptable, you can pass
        an ``overwrite=True``. If that's not acceptable, you may be able to use
        ``Item.partial_save`` to only write the changed field data.

        Optionally accepts an ``overwrite`` parameter, which should be a
        boolean. If you provide ``True``, the item will be forcibly overwritten
        within DynamoDB, even if another process changed the data in the
        meantime. (Default: ``False``)

        Returns ``True`` on success, ``False`` if no save was performed.

        Example::

            >>> user['last_name'] = 'Doh!'
            # All data on the Item is sent to DynamoDB.
            >>> user.save()

            # If it fails, you can overwrite.
            >>> user.save(overwrite=True)

        FNrK   )r3   rE   rC   r
   Z	_put_itemr5   )r   	overwriterD   rB   rO   r   r   r   save  s    z	Item.savec                 C   s   |   }| jjf |S )z
        Deletes the item's data to DynamoDB.

        Returns ``True`` on success.

        Example::

            # Buh-bye now.
            >>> user.delete()

        )r;   r
   Zdelete_item)r   r:   r   r   r   delete  s    zItem.delete)NF)N)N)N)F)r   r   r   __doc__r   r   r   r   r   r   r    r   r"   r#   r%   __nonzero__r1   r3   r5   r6   r9   r;   r=   rC   r,   rE   rJ   rP   rR   rS   r   r   r   r   r	   	   s6   
9
$
	
4	$.
-r	   N)copyr   objectr   r	   r   r   r   r   <module>   s   