from aioriak.datatypes import TYPES
def bucket_property(name, doc=None):
def _prop_getter(self):
return self.get_property(name)
def _prop_setter(self, value):
return self.set_property(name, value)
return property(_prop_getter, _prop_setter, doc=doc)
[docs]class Bucket:
'''
The ``Bucket`` object allows you to access and change information
about a Riak bucket, and provides async methods to create or retrieve
objects within the bucket.
'''
[docs] def __init__(self, client, name, bucket_type):
'''
Returns a new ``Bucket`` instance.
:param client: A :class:`RiakClient <aioriak.client.RiakClient>`
instance
:type client: :class:`RiakClient <aioriak.client.RiakClient>`
:param name: The bucket name
:type name: string
:param bucket_type: The parent bucket type of this bucket
:type bucket_type: :class:`BucketType`
'''
if not isinstance(name, str):
raise TypeError('Bucket name must be a string')
if not isinstance(bucket_type, BucketType):
raise TypeError('Parent bucket type must be a BucketType instance')
self._client = client
self.name = name
self.bucket_type = bucket_type
self._encoders = {}
self._decoders = {}
self._resolver = None
def _get_resolver(self):
if callable(self._resolver):
return self._resolver
elif self._resolver is None:
return self._client.resolver
else:
raise TypeError("resolver is not a function")
def _set_resolver(self, value):
if value is None or callable(value):
self._resolver = value
else:
raise TypeError("resolver is not a function")
resolver = property(_get_resolver, _set_resolver,
doc='''The sibling-resolution function for this
bucket. If the resolver is not set, the
client's resolver will be used.''')
allow_mult = bucket_property(
'allow_mult',
doc='''If set to True, then writes with conflicting data will be stored
and returned to the client.
:type bool: boolean''')
[docs] def get_decoder(self, content_type):
'''
Get the decoding function for the provided content type for
this bucket.
:param content_type: the requested media type
:type content_type: str
:rtype: function
'''
if content_type in self._decoders:
return self._decoders[content_type]
else:
return self._client.get_decoder(content_type)
[docs] def get_encoder(self, content_type):
'''
Get the encoding function for the provided content type for
this bucket.
:param content_type: the requested media type
:type content_type: str
:param content_type: Content type requested
'''
if content_type in self._encoders:
return self._encoders[content_type]
else:
return self._client.get_encoder(content_type)
[docs] def set_encoder(self, content_type, encoder):
'''
Set the encoding function for the provided content type for
this bucket.
:param content_type: the requested media type
:type content_type: str
:param encoder: an encoding function, takes a single object
argument and returns a string data as single argument.
:type encoder: function
'''
self._encoders[content_type] = encoder
return self
[docs] def set_decoder(self, content_type, decoder):
'''
Set the decoding function for the provided content type for
this bucket.
:param content_type: the requested media type
:type content_type: str
:param decoder: a decoding function, takes a string and
returns a Python type
:type decoder: function
'''
self._decoders[content_type] = decoder
return self
[docs] async def set_property(self, key, value):
'''
Set a bucket property.
:param key: Property to set.
:type key: string
:param value: Property value.
:type value: mixed
'''
return await self.set_properties({key: value})
[docs] async def get_property(self, key):
'''
Retrieve a bucket property.
:param key: The property to retrieve.
:type key: string
:rtype: mixed
'''
return (await self.get_properties())[key]
[docs] async def set_properties(self, props):
'''
Set multiple bucket properties in one call.
:param props: A dictionary of properties
:type props: dict
'''
await self._client.set_bucket_props(self, props)
[docs] async def get_properties(self):
'''
Retrieve a dict of all bucket properties.
:rtype: dict
'''
return await self._client.get_bucket_props(self)
[docs] async def get_keys(self):
'''
Return all keys within the bucket.
:rtype: list of keys
'''
return await self._client.get_keys(self)
[docs] async def get(self, key):
'''
Retrieve an :class:`~aioriak.riak_object.RiakObject` or
:class:`~aioriak.datatypes.Datatype`, based on the presence and value
of the :attr:`datatype <BucketType.datatype>` bucket property.
:param key: Name of the key.
:type key: string
:rtype: :class:`RiakObject <aioriak.riak_object.RiakObject>` or
:class:`~aioriak.datatypes.Datatype`
'''
if await self.bucket_type.get_datatype():
return await self._client.fetch_datatype(self, key)
from aioriak.riak_object import RiakObject
obj = RiakObject(self._client, self, key)
return await obj.reload()
[docs] async def new(self, key=None, data=None, content_type='application/json',
encoded_data=None):
'''
A shortcut for manually instantiating a new
:class:`~aioriak.riak_object.RiakObject` or a new
:class:`~aioriak.datatypes.Datatype`, based on the presence and value
of the :attr:`datatype <aioriak.bucket.BucketType.datatype>` bucket
property. When the bucket contains a
:class:`~aioriak.datatypes.Datatype`, all arguments are ignored except
``key``, otherwise they are used to
initialize the :class:`~aioriak.riak_object.RiakObject`.
:param key: Name of the key. Leaving this to be None (default)
will make Riak generate the key on store.
:type key: str
:param data: The data to store in a
:class:`~aioriak.riak_object.RiakObject`, see
:attr:`RiakObject.data <aioriak.riak_object.RiakObject.data>`.
:type data: object
:param content_type: The media type of the data stored in the
:class:`~aioriak.riak_object.RiakObject`, see
:attr:`RiakObject.content_type
<aioriak.riak_object.RiakObject.content_type>`.
:type content_type: str
:param encoded_data: The encoded data to store in a
:class:`~aioriak.riak_object.RiakObject`, see
:attr:`RiakObject.encoded_data
<aioriak.riak_object.RiakObject.encoded_data>`.
:type encoded_data: str
:rtype: :class:`~aioriak.riak_object.RiakObject` or
:class:`~aioriak.datatypes.Datatype`
'''
from aioriak import RiakObject
datatype = await self.bucket_type.get_datatype()
if datatype:
return TYPES[datatype](bucket=self, key=key)
obj = RiakObject(self._client, self, key)
obj.content_type = content_type
if data is not None:
obj.data = data
if encoded_data is not None:
obj.encoded_data = encoded_data
return obj
[docs] async def delete(self, key, **kwargs):
'''
Deletes a key from Riak. Short hand for
``bucket.new(key).delete()``. See :meth:`RiakClient.delete()
<aioriak.client.RiakClient.delete>` for options.
:param key: The key for the object
:type key: string
:rtype: RiakObject
'''
return await (await self.new(key)).delete(**kwargs)
async def get_index(self, index, startkey, endkey=None,
return_terms=None, max_results=None,
continuation=None, timeout=None, term_regex=None):
"""
Queries a secondary index over objects in this bucket,
returning keys or index/key pairs.
See :meth:`RiakClient.get_index()
<aioriak.client.RiakClient.get_index>` for more details.
"""
return await self._client.get_index(
self, index, startkey, endkey, return_terms, max_results,
continuation, timeout, term_regex)
def __repr__(self):
if self.bucket_type.is_default():
return '<Bucket {}>'.format(self.name)
else:
return '<Bucket {}/{}>'.format(self.bucket_type.name,
self.name)
[docs]class BucketType:
'''
The ``BucketType`` object allows you to access and change
properties on a Riak bucket type and access buckets within its
namespace.
Async implementation of riak.bucket.BucketType
'''
[docs] def __init__(self, client, name):
'''
Returns a new ``BucketType`` instance.
:param client: A :class:`RiakClient <aioriak.client.RiakClient>`
instance
:type client: :class:`RiakClient <aioriak.client.RiakClient>`
:param name: The bucket-type's name
:type name: string
'''
self._client = client
self.name = name
def __repr__(self):
return "<BucketType {0}>".format(self.name)
def __hash__(self):
return hash((self.name, self._client))
def __eq__(self, other):
if isinstance(other, self.__class__):
return hash(self) == hash(other)
else:
return False
def __ne__(self, other):
if isinstance(other, self.__class__):
return hash(self) != hash(other)
else:
return True
def _get_resolver(self):
if callable(self._resolver):
return self._resolver
elif self._resolver is None:
return self._client.resolver
else:
raise TypeError("resolver is not a function")
def _set_resolver(self, value):
if value is None or callable(value):
self._resolver = value
else:
raise TypeError("resolver is not a function")
resolver = property(_get_resolver, _set_resolver,
doc='''The sibling-resolution function for this
bucket. If the resolver is not set, the
client's resolver will be used.''')
[docs] def is_default(self):
'''
Whether this bucket type is the default type, or a user-defined type.
:rtype: bool
'''
return self.name == 'default'
[docs] async def get_property(self, key):
'''
Retrieve a bucket-type property.
:param key: The property to retrieve.
:type key: string
:rtype: mixed
'''
return await self.get_properties()[key]
[docs] async def set_property(self, key, value):
'''
Set a bucket-type property.
:param key: Property to set.
:type key: string
:param value: Property value.
:type value: mixed
'''
await self.set_properties({key: value})
[docs] async def get_properties(self):
'''
Retrieve a dict of all bucket-type properties.
:rtype: dict
'''
return await self._client.get_bucket_type_props(self)
[docs] async def set_properties(self, props):
'''
Set multiple bucket-type properties in one call.
:param props: A dictionary of properties
:type props: dict
'''
await self._client.set_bucket_type_props(self, props)
[docs] def bucket(self, name):
'''
Gets a bucket that belongs to this bucket-type.
:param name: the bucket name
:type name: str
:rtype: :class:`Bucket`
'''
return self._client.bucket(name, self)
[docs] async def get_buckets(self):
'''
Get the list of buckets under this bucket-type as
:class:`Bucket <aioriak.bucket.Bucket>` instances.
.. warning:: Do not use this in production, as it requires
traversing through all keys stored in a cluster.
:rtype: list of :class:`Bucket <aioriak.bucket.Bucket>`
instances
'''
return await self._client.get_buckets(bucket_type=self)
async def get_datatype(self):
'''
The assigned datatype for this bucket type, if present.
:rtype: None or string
'''
if not hasattr(self, '_datatype'):
self._datatype = (await self.get_properties()).get('datatype')
return self._datatype