Source code for pouchdb.objectstorage

#	Copyright 2014, Marten de Vries
#
#	Licensed under the Apache License, Version 2.0 (the "License");
#	you may not use this file except in compliance with the License.
#	You may obtain a copy of the License at
#
#	http://www.apache.org/licenses/LICENSE-2.0
#
#	Unless required by applicable law or agreed to in writing, software
#	distributed under the License is distributed on an "AS IS" BASIS,
#	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#	See the License for the specific language governing permissions and
#	limitations under the License.

"""The objectstorage module allows you to save ordinary Python objects
directly into PouchDB. The (de)serializing is handled by the
`jsonpickle module <https://jsonpickle.github.io/>`_.

*******
Example
*******

>>> from pouchdb.objectstorage import load, store
>>> from jsonpickle._samples import Thing
>>> 
>>> env = setup()
>>> db = env.PouchDB("objectstorage_test")
>>> thingy = Thing("abc")
>>> 
>>> store(thingy, db, "the_id")
Thing("abc")
>>> new_thingy = load(db, "the_id")
>>> print new_thingy.name
abc
>>> 
>>> env.destroy("objectstorage_test")

"""

try:
	import jsonpickle.pickler
	import jsonpickle.unpickler
except ImportError: #pragma: no cover
	raise ImportError("pouchdb.objectstorage requires the jsonpickle module to be installed.")
import collections
import pouchdb.info

_KEY_PREFIX = pouchdb.info.name.lower() + "-"

[docs]def store(obj, db, id=None, rev=None, prefix=None): """Stores `obj` into `db`. :param obj: Any Python object that ``jsonpickle`` can handle. (i.e. most objects.) :param pouchdb.SyncPouchDB db: A database as returned by ``pouchdb.setup().PouchDB(db_name)``. This **can't** be a database as generated by the asynchronous API. :param str id: Used as the ``_id`` field in PouchDB. If this is ``None`` and ``obj.id`` exists, that is used. The fallback is a UUID. :param str rev: Used as the ``_rev`` field in PouchDB. If this is ``None`` and ``obj.rev`` exists, that is used. Otherwise a new document is assumed (with no ``_rev`` yet). :param str prefix: a serialization as returned by ``jsonpickle`` can have a field starting with '_' in a dictionary. That clashes with PouchDB, which can't. To work around that, every key is prefixed with this argument **if the situation occurs**. When no prefix is specified it'll be: '``%s``'. :returns: `obj` -- the same object as the parameter on which ``obj.id`` and ``obj.rev`` will have been set. """ if not prefix: prefix = _KEY_PREFIX if hasattr(obj, "id"): id = id or obj.id del obj.id if hasattr(obj, "rev"): rev = rev or obj.rev del obj.rev doc = jsonpickle.pickler.Pickler().flatten(obj) if any(k.startswith("_") for k in doc): doc = {prefix + k:v for k, v in doc.iteritems()} if id: doc["_id"] = id if rev: doc["_rev"] = rev resp = db.post(doc) obj.id = resp.id obj.rev = resp.rev return obj
store.__doc__ = store.__doc__ % _KEY_PREFIX
[docs]def load(db, id, rev=None, prefix=None): """Loads an earlier under `id` stored object from `db`. :param str id: The ``_id`` to look for in the database. :param str rev: The ``_rev`` to look for in the database. When not specified the latest revision is used. :param str prefix: see :func:`store`'s parameter with the same name. Should equal the one used to store the object, otherwise the result is **undefined**. :returns: the earlier stored object. """ if not prefix: prefix = _KEY_PREFIX doc = db.get(id, rev=rev) data = {} for key, value in doc.iteritems(): if key in ["_id", "_rev"]: continue if key.startswith(prefix): key = key[len(prefix):] data[key] = _normalizeDicts(value) obj = jsonpickle.unpickler.Unpickler().restore(data) obj.id = doc["_id"] obj.rev = doc["_rev"] return obj
def _normalizeDicts(obj): if isinstance(obj, collections.Mapping): return {k:_normalizeDicts(v) for k, v in obj.iteritems()} if isinstance(obj, collections.MutableSequence): return [_normalizeDicts(x) for x in obj] return obj