'''
Copyright 2013 Basho Technologies, Inc.
This file is provided to you 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.
'''
from aioriak.error import RiakError
[docs]class RiakContent(object):
'''
The RiakContent holds the metadata and value of a single sibling
within a RiakObject. RiakObjects that have more than one sibling
are considered to be in conflict.
'''
def __init__(self, robject, data=None, encoded_data=None, charset=None,
content_type='application/json', content_encoding=None,
last_modified=None, etag=None, usermeta=None, links=None,
indexes=None, exists=False):
self._robject = robject
self._data = data
self._encoded_data = encoded_data
self.charset = charset
self.content_type = content_type
self.content_encoding = content_encoding
self.last_modified = last_modified
self.etag = etag
self.usermeta = usermeta or {}
self.links = links or []
self.indexes = indexes or set()
self.exists = exists
def _get_data(self):
if self._encoded_data is not None and self._data is None:
self._data = self._deserialize(self._encoded_data)
self._encoded_data = None
return self._data
def _set_data(self, value):
self._encoded_data = None
self._data = value
data = property(_get_data, _set_data, doc='''
The data stored in this object, as Python objects. For the raw
data, use the `encoded_data` property. If unset, accessing
this property will result in decoding the `encoded_data`
property into Python values. The decoding is dependent on the
`content_type` property and the bucket's registered decoders.
:type mixed''')
def _get_encoded_data(self):
if self._data is not None and self._encoded_data is None:
self._encoded_data = self._serialize(self._data)
self._data = None
return self._encoded_data
def _set_encoded_data(self, value):
self._data = None
self._encoded_data = value
encoded_data = property(_get_encoded_data, _set_encoded_data, doc='''
The raw data stored in this object, essentially the encoded
form of the `data` property. If unset, accessing this property
will result in encoding the `data` property into a string. The
encoding is dependent on the `content_type` property and the
bucket's registered encoders.
:type str''')
def _serialize(self, value):
encoder = self._robject.bucket.get_encoder(self.content_type)
if encoder:
return encoder(value)
elif isinstance(value, str):
return value.encode()
else:
raise TypeError('No encoder for non-string data '
'with content type "{0}"'.
format(self.content_type))
def _deserialize(self, value):
decoder = self._robject.bucket.get_decoder(self.content_type)
if decoder:
return decoder(value)
else:
raise TypeError('No decoder for content type "{0}"'.
format(self.content_type))
def add_index(self, field, value):
'''
add_index(field, value)
Tag this object with the specified field/value pair for
indexing.
:param field: The index field.
:type field: string
:param value: The index value.
:type value: string or integer
:rtype: :class:`RiakObject <riak.riak_object.RiakObject>`
'''
if field[-4:] not in ("_bin", "_int"):
raise RiakError("Riak 2i fields must end with either '_bin'"
" or '_int'.")
self.indexes.add((field, value))
return self._robject
def remove_index(self, field=None, value=None):
'''
remove_index(field=None, value=None)
Remove the specified field/value pair as an index on this
object.
:param field: The index field.
:type field: string
:param value: The index value.
:type value: string or integer
:rtype: :class:`RiakObject <riak.riak_object.RiakObject>`
'''
if not field and not value:
self.indexes.clear()
elif field and not value:
for index in [x for x in self.indexes if x[0] == field]:
self.indexes.remove(index)
elif field and value:
self.indexes.remove((field, value))
else:
raise RiakError("Cannot pass value without a field"
" name while removing index")
return self._robject
remove_indexes = remove_index
def set_index(self, field, value):
'''
Works like :meth:`add_index`, but ensures that there is only
one index on given field. If other found, then removes it
first.
:param field: The index field.
:type field: string
:param value: The index value.
:type value: string or integer
:rtype: :class:`RiakObject <riak.riak_object.RiakObject>`
'''
to_rem = set((x for x in self.indexes if x[0] == field))
self.indexes.difference_update(to_rem)
return self.add_index(field, value)
def add_link(self, obj, tag=None):
'''
Add a link to a RiakObject.
:param obj: Either a RiakObject or 3 item link tuple consisting
of (bucket, key, tag).
:type obj: mixed
:param tag: Optional link tag. Defaults to bucket name. It is ignored
if ``obj`` is a 3 item link tuple.
:type tag: string
:rtype: :class:`RiakObject <riak.riak_object.RiakObject>`
'''
if isinstance(obj, tuple):
newlink = obj
else:
newlink = (obj.bucket.name, obj.key, tag)
self.links.append(newlink)
return self._robject