flywheel 0.5.4
SQLAlchemy-style ORM for Amazon's DynamoDB
License: MIT
Keywords: aws dynamo dynamodb orm odm

Flywheel
========
:Build: |build|_ |coverage|_
:Documentation: http://flywheel.readthedocs.org/
:Downloads: http://pypi.python.org/pypi/flywheel
:Source: https://github.com/stevearc/flywheel

.. |build| image:: https://travis-ci.org/stevearc/flywheel.png?branch=master
.. _build: https://travis-ci.org/stevearc/flywheel
.. |coverage| image:: https://coveralls.io/repos/stevearc/flywheel/badge.png?branch=master
.. _coverage: https://coveralls.io/r/stevearc/flywheel?branch=master

Object mapper for Amazon's DynamoDB

**END OF LIFE WARNING**: I haven't personally used this project, or even written
much python, since early 2014. I will continue to respond to bugs and pull
requests, but I am no longer doing active development. My apologies to those of
you who have come to rely on Flywheel; I wish I had the time to continue it. If
there is anyone in the community interested in becoming the new maintainer and
continuing to move development forward, send me an email and we can discuss.

If you are looking for an alternative, I can recommend `PynamoDB
<https://github.com/jlafon/PynamoDB>`_.

Getting Started
===============
This is what a basic model looks like (schema taken from this `DynamoDB
API documentation
<http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html>`_)

::

    from flywheel import Model, Field, GlobalIndex

    class GameScore(Model):
        __metadata__ = {
            'global_indexes': [
                GlobalIndex('GameTitleIndex', 'title', 'top_score')
            ],
        }
        userid = Field(hash_key=True)
        title = Field(range_key=True)
        top_score = Field(type=int)
        top_score_time = Field(type=datetime)
        wins = Field(type=int)
        losses = Field(type=int)

        def __init__(self, title, userid):
            self.title = title
            self.userid = userid

Create a new top score

::

    >>> score = GameScore('Master Blaster', 'abc')
    >>> score.top_score = 9001
    >>> score.top_score_time = datetime.utcnow()
    >>> engine.sync(score)

Get all top scores for a user

::

    >>> scores = engine.query(GameScore).filter(userid='abc').all()

Get the top score for Galaxy Invaders

::

    >>> top_score = engine.query(GameScore).filter(title='Galaxy Invaders')\
    ...     .first(desc=True)

Atomically increment a user's "wins" count on Alien Adventure

::

    >>> score = GameScore('Alien Adventure', 'abc')
    >>> score.incr_(wins=1)
    >>> engine.sync(score)

Get all scores on Comet Quest that are over 9000

::

    >>> scores = engine.query(GameScore).filter(GameScore.top_score > 9000,
    ...                                         title='Comet Quest').all()


Changelog
=========

0.5.4
-----
* Constrain version of ``dynamo3`` dependency to avoid breakage

0.5.3
-----
* Bug fix: Fix refresh when using custom-typed primary keys 

0.5.2
-----
* Bug fix: Change limit behavior to match docs. ``query().limit()`` will limit the number of results, ``query().scan_limit()`` will limit number of items scanned 

0.5.1
-----
* Feature: Add ``update_schema()`` method to Engine 

0.5.0
-----
* **Breakage**: Removing support for overflow fields. The only fields flywheel will care about now are those that are explicitly set as a Field()
* Flywheel no longer forces raise_on_conflict to be True when you sync changes to fields that are part of a composite field. It is now up to the user to avoid putting their composite fields into an inconsistent state.
* Feature: sync() has a new argument, ``no_read``, which changes the behavior for syncing models with no changes. Instead of performing a GET, it will leave them as-is. This should make it easer to perform batch syncs without worrying as much about wasted bandwidth on GETs. 
* ``Field`` has renamed the ``data_type`` argument to ``type`` (``data_type`` will still work)

0.4.11
------
* Bug fix: Boolean overflow fields no longer decoded as decimals 

0.4.10
------
* Feature: Add ``exists()`` method to Engine 

0.4.9
-----
* Feature: Add ``save()`` method to Models 
* Feature: Add ``update_field()`` method to Engine 

0.4.8
-----
* Bug fix: Bad function call in ``index_pk_dict_``

0.4.7
-----
* New ``index_pk_dict_`` method for constructing `exclusive_start_key` for index queries 

0.4.6
-----
* Pass exclusive_start_key through to dynamo3 

0.4.5
-----
* Bug fix: Calling refresh() could sometimes crash from unordered results.

0.4.4
-----
* Bug fix: Mutable field defaults are no longer shared among model instances

0.4.3
-----
* Bug fix: Incorrect ``ConditionalCheckFailedException`` when syncing changes to a Composite field.
* Allow ``DateTimeType`` to be stored as a naive datetime.

0.4.2
-----
* Make the ``dict``, ``list``, and ``bool`` types backwards-compatible with the old json-serialized format 
* Allow queries to use ``in``, ``not null``, and a few other constraints that were missing 
* Models are smarter about marking fields as dirty for sync 
* Stopped using deprecated ``expected`` syntax for dynamo3

0.4.1
-----
* **Warning**: Stored datetime objects will now be timezone-aware 
* **Warning**: Stored datetime objects will now keep their microseconds 

0.4.0
-----
* **Breakage**: Dropping support for python 3.2 due to lack of botocore support
* **Breakage**: Changing the ``list``, ``dict``, and ``bool`` data types to use native DynamoDB types instead of JSON serializing
* **Breakage** and bug fix: Fixing serialization of ``datetime`` and ``date`` objects (for more info see the commit) 
* Feature: Can now do 'contains' filters on lists
* Feature: Fields support multiple validation checks
* Feature: Fields have an easy way to enforce non-null values (``nullable=False``)

Data type changes are due to `an update in the DynamoDB API
<https://aws.amazon.com/blogs/aws/dynamodb-update-json-and-more/>`_

0.3.0
-----
* **Breakage**: Engine namespace is slightly different. If you pass in a string it will be used as the table name prefix with no additional '-' added.

0.2.1
-----
* **Breakage**: Certain queries may now require you to specify an index where it was auto-detected before
* Feature: Queries can now filter on non-indexed fields
* Feature: More powerful "sync-if" constraints
* Feature: Can OR together filter constraints in queries

All changes are due to an `update in the DynamoDB API
<http://aws.amazon.com/blogs/aws/improved-queries-and-updates-for-dynamodb/>`_

0.2.0
-----
* **Breakage**: Engine no longer accepts boto connections (using dynamo3 instead)
* **Breakage**: Removing S3Type (no longer have boto as dependency)
* Feature: Support Python 3.2 and 3.3
* Feature: ``.count()`` terminator for queries 
* Feature: Can override throughputs in ``Engine.create_schema()`` 
* Bug fix: Engine ``namespace`` is truly isolated 

0.1.3
-----
* Bug fix: Some queries fail when global index has no range key 

0.1.2
-----
* Bug fix: Field names can begin with an underscore 
* Feature: Models have a nice default __init__ method 

0.1.1
-----
* Bug fix: Can call ``incr_()`` on models that have not been saved yet 
* Bug fix: Model comparison with ``None`` 

0.1.0
-----
* First public release