# -*- coding: utf-8 -*-
"""
The base datastore implementation. Define the DataStore class from
wich each DataStore inherit
"""
from abc import ABCMeta, abstractmethod
from werkzeug.exceptions import BadRequest
[docs]class DataStore(object):
"""
define a source of data. Can be anything fron database to other
api, files and so one
"""
__metaclass__ = ABCMeta
def __init__(self, ressource_config, model, **options):
"""
Set the ressource datastore
"""
self.ressource_config = ressource_config
self.make_options(options)
self.model = model()
def make_options(self, options):
if options.get("validators", None):
self.validators = []
for elem in options["validators"]:
self.validators.append(elem)
else:
self.validators = None
self.partial = options.get("partial", None)
@abstractmethod
[docs] def get(self, identifier):
"""
Should return a dictionnary representing the ressource matching the
identifier or raise a NotFound exception.
.. note::
Not implemented by base DataStore class
"""
raise NotImplementedError
@abstractmethod
[docs] def create(self, data):
"""
data is a dict containing the representation of the
ressource. This method should call
:meth:`~.DataStore.validate`,
create the data in the datastore and return the ressource
identifier
.. note::
Not implemented by base DataStore class
"""
raise NotImplementedError
@abstractmethod
[docs] def update(self, obj, data):
"""
should be able to call :meth:`~.DataStore.get` to retreive the
object to be updated, :meth:`~.DataStore.validate_fields` and
return the updated object
.. note::
Not implemented by base DataStore class
"""
raise NotImplementedError
@abstractmethod
[docs] def delete(self, identifier):
"""
should be able to validate the existence of the object in the
ressource and remove it from the datastore
.. note::
Not implemented by base DataStore class
"""
raise NotImplementedError
@abstractmethod
[docs] def get_list(self, offset=None, count=None, **kwargs):
"""
This method is called each time you want a set of data.
Data could be paginated and filtered.
Should call :meth:`~.DataStore.filter`
and return :meth:`~.DataStore.paginate`
.. note::
Not implemented by base DataStore class
"""
raise NotImplementedError
@abstractmethod
[docs] def filter(self, **kwargs):
"""
should return a way to filter the ressource according to
kwargs. It is not mandatory to actualy retreive the
ressources as they will be paginated just after the filter
call. If you retreive the wole filtered ressources you loose
the pagination advantage. The point here is to prepare the
filtering. Look at SQLiteDataStore.filter for an example.
.. note::
Not implemented by base DataStore class
"""
raise NotImplementedError
[docs] def paginate(self, data, offset, count):
"""
Paginate sould return all the object if no pagination options
have been set or only a subset of the ressources if pagination
options exists.
"""
if not count:
return data[offset:]
return data[offset:offset+count]
[docs] def validate(self, data):
"""
Check if data send are valid for object creation. Validate
Chek that each required fields are in data and check for their
type too.
Used to create new ressources
"""
if not isinstance(data, dict):
raise BadRequest()
for field in self.model.fields:
for validator in field.validators:
if field.name not in data and field.options.get(
"required", None) is True:
raise BadRequest(
"{0} is missing. Cannot create the ressource".format(
field.name)
)
if hasattr(validator, "need_datastore"):
if not validator.validate(data[field.name], self):
print "OUPS"
raise BadRequest("{0} does not validate".format(
field.name))
else:
if field.name in data:
if not validator.validate(data[field.name]):
raise BadRequest(
"{0} does not validate".format(
field.name))
if self.validators:
for elem in self.validators:
elem.validate(self, data)
[docs] def validate_fields(self, data):
"""
Validate only some fields of the ressource.
Used to update existing objects
"""
if not isinstance(data, dict):
raise BadRequest()
for k, v in data.iteritems():
if k not in self.model.get_fields_name():
raise BadRequest()
field = self.model.get_field(k)
for validator in field.validators:
if not validator.validate(v):
raise BadRequest()
if self.validators:
for elem in self.validators:
elem.validate(self, data)