GridFS
======

MongoKit implements GridFS support and brings some helpers
to facilitate the use of relative small files.

Let's create a document ``Doc`` which have two attachment in
GridFS  named as  `source` and `template`:

>>> from mongokit import *
>>> class Doc(Document):
...        structure = {
...            'title':unicode,
...        }
...        gridfs = {'files':['source', 'template']}


You might want to be able to add file in gridfs on the fly without knowing
their name.  The new API allow to add "containers" to gridfs. So, the gridfs
declaration look like this ::

    gridfs = {
      'files':['source', 'template'],
      'containers': ['images'],
    }

As you can see, nothing hard. We just declare our attachment files
in the `gridfs` attribute. Filling this attribute will generate
an `fs` attribute at runtime. This `fs` attribute is actually an
object which deal with GridFS.


>>> connection = Connection()
>>> connection.register([Doc])
>>> doc = connection.test.tutorial.Doc()
>>> doc['title'] = u'Hello'
>>> doc.save()

Before using gridfs attachment, you have to save the document.
This is required as under the hood, mongokit use the document
``_id`` to link with GridFS files.

The simple way
--------------

All gridfs attachments are accessible via the `fs` object.
Now, we can fill the ``source`` and ``template``:

>>> doc.fs.source = "Hello World !"
>>> doc.fs.template = "My pretty template"

And that's it ! By doing this, MongoKit will open a GridFile,
fill it with the value, and close it.

Note that you have to be careful to the type : attachments
only accept string.

You can read any attachment in a very simple way :

>>> doc.fs.source
'Hello World !'


You can add any image you want to the container "images":

>>> doc.fs.images['image1.png'] = "..."
>>> doc.fs.images['image1.png']
'...'
>>> doc.fs.images['image2.png'] = '...'

This is very useful when you want of store a number of file but you don't
know their names.


If you have python-magic installed (``sudo easy_install -U python-magic``),
the content-type of the file is automatically guessed. To access to it, you
have to use the "full way".

.. topic:: new in version 0.5.11 

    There were many problems with the python-magic support so it has been removed.


If you do not know stored file names, you can list them by iterate::

    >>> [f.name for f in doc.fs]
    ['source', 'template']

You can list a container as well. The container name is accessible via the `container` attribute::

    >>> for f in doc.fs.images:
    ...    print '%s/%s' % (f.container, f.name)
    images/image1.png
    images/image2.png


The full way
------------

While the previous method is very easy, it might not be enougth
if you're dealing with very big files or want to use some file
related feature (for instance, using seek to not have to load
all the file in memory)

You can do that with using the `get_last_version()` method on the ``fs`` object.

>>> f = doc.fs.get_last_version("source")
>>> f.read(10)

If you want to create a file and write in it, you can do that with using the
`new_file()` method on the ``fs`` object.  The `new_file()` method take the
file name and all other properties pymongo
accepts here::

>>> f = doc.fs.new_file('source')
>>> f.write("Hello World again !")
>>> f.close() 


By supporting PyMongo 1.6 you can use the advanced ``with`` keyword
to handle write operations:

   >>> with doc.fs.new_file("source") as f:
   ...     f.write("Hello World again !")
   ...

You can add any image you want to the container "images":

    >>> f = doc.fs.images.new_file('image1.png')
    >>> f.write('...')
    >>> f.close()
    >>> f = doc.fs.images.get_last_version('image1.png')
    >>> f.read(10)


All PyMongo API is supported::

    >>> id = doc.fs.put("Hello World", filename="source")
    >>> doc.fs.get(id).read()
    'Hello World'
    >>> doc.fs.get_last_version("source")
    <gridfs.grid_file.GridOut object at 0x1573610>
    >>> doc.fs.get_last_version("source").read()
    'Hello World'
    >>> f = doc.fs.new_file("source")
    >>> f.write("New Hello World!")
    >>> f.close()
    >>> doc.fs.source
    'New Hello World!'
    >>> new_id = doc.fs.get_last_version("source")._id
    >>> doc.fs.delete(new_id)
    >>> doc.fs.source
    'Hello World'

