Module firestore.db
This is a collection of tools used by mantle Database packages, the include property types and common errors
Source code
"""
This is a collection of tools used by mantle Database packages, the include property types and common errors
"""
import json
import pickle
from datetime import datetime, date
from google.cloud.firestore import SERVER_TIMESTAMP
class Property(object):
"""
A class describing a typed, persisted attribute of a database entity
"""
def __init__(self, default=None, required=False):
"""
Args:
default: The default value of the property
required: Enforce the property value to be provided
"""
if type(self) is Property:
raise Exception("You must extend Property")
self.default = default
self.required = required
self.name = None
def __get_user_value__(self, base_value):
"""
Convert value from database to a value usable by the user
Args:
base_value: The current value from db
Returns:
user_value expected to be of the specified type
"""
raise NotImplementedError
def __get_base_value__(self, user_value):
"""
Convert value to database acceptable format
Args
:param user_value: Current user_value
:return: base_value
"""
raise NotImplementedError
def __type_check__(self, user_value, data_types):
"""
Check whether this value has the right data type
Args:
user_value: The user_value you want to confirm
data_types: Type/Types to check against
Returns:
Any
"""
if self.required and self.default is None and user_value is None:
raise InvalidValueError(self, user_value)
# Assign a default value if None is provided
if user_value is None:
user_value = self.default
if not isinstance(user_value, data_types) and user_value is not None:
raise InvalidValueError(self, user_value)
return user_value
class TextProperty(Property):
"""An Property whose value is a text string of unlimited length.
I'ts not advisable to index this property
"""
def __get_base_value__(self, user_value):
return self.__type_check__(user_value, str)
def __get_user_value__(self, base_value):
return base_value
class StringProperty(Property):
"""
An indexed Property whose value is a text string of limited length.
Args:
default: Default value for this property
length (int): The maximum length of this property
required (bool): Enforce whether this value can be empty
"""
def __init__(self, default=None, length=255, required=False):
super(StringProperty, self).__init__(default=default, required=required)
self.length = length
def __get_base_value__(self, user_value):
user_value = self.__type_check__(user_value, str)
if user_value is not None and len(user_value) > self.length:
raise InvalidValueError(self, user_value)
return user_value
def __get_user_value__(self, base_value):
return base_value
class IntegerProperty(Property):
"""A Property whose value is a Python int or long"""
def __get_base_value__(self, user_value):
return self.__type_check__(user_value, int)
def __get_user_value__(self, base_value):
return base_value
class FloatingPointNumberProperty(Property):
"""A Property whose value is a Python float.
Note: int and long are also allowed.
"""
def __get_base_value__(self, user_value: float):
user_value = self.__type_check__(user_value, (int, float))
return user_value
def __get_user_value__(self, base_value):
return base_value
class BlobProperty(Property):
"""A Property whose value is a byte string. It may be compressed."""
def __get_base_value__(self, user_value):
return self.__type_check__(user_value, (bytes, bytearray))
def __get_user_value__(self, base_value):
return base_value
class ListProperty(Property):
"""A List property"""
def __init__(self, property_type: Property):
super(ListProperty, self).__init__(default=[])
self.property_type = property_type
def __get_base_value__(self, user_value: list):
user_value = self.__type_check__(user_value, (list))
user_value = [self.property_type.__get_base_value__(value) for value in user_value]
return user_value
def __get_user_value__(self, base_value):
return base_value
class ReferenceProperty(Property):
def __init__(self, entity, required=False):
from firestore import Entity
if not issubclass(entity, Entity):
raise ReferencePropertyError("A reference property must reference another model")
super(ReferenceProperty, self).__init__(required=required)
self.entity = entity
def __get_base_value__(self, user_value):
user_value = self.__type_check__(user_value, (self.entity))
if not user_value:
return user_value
if not user_value.id:
raise ReferencePropertyError("A reference must be put first before it can be referenced")
return user_value.__document__()
def __get_user_value__(self, base_value):
if not base_value:
return None
user_data = self.entity.__get_user_data__(base_value.get().to_dict())
return self.entity(id=base_value.id, **user_data)
class JsonProperty(Property):
"""A property whose value is any Json-encodable Python object.
"""
def __init__(self, required=False):
super(JsonProperty, self).__init__(required=required, default={})
def __get_base_value__(self, user_value):
if isinstance(user_value, str):
try:
user_value = json.loads(user_value)
except json.JSONDecodeError:
raise InvalidPropertyError(self, "Dict property must be valid JSON")
return self.__type_check__(user_value, dict)
def __get_user_value__(self, base_value):
return base_value
class BooleanProperty(Property):
"""A Property whose value is a Python bool."""
def __get_base_value__(self, user_value):
return self.__type_check__(user_value, bool)
def __get_user_value__(self, base_value):
return base_value
class DateTimeProperty(Property):
"""A Property whose value is a datetime object.
Note: auto_now_add can be overridden by setting the value before writing the entity.
Args:
default (datetime)
required (bool): Enforce that this property can't be submitted when empty
auto_now (bool): Set to the current time every time the model is updated
auto_add_now (bool): Set to the current time when a record is created
"""
def __init__(self, default=None, required=False, auto_now=False, auto_add_now=False):
if not default and auto_add_now:
default = SERVER_TIMESTAMP
super(DateTimeProperty, self).__init__(default=default, required=required)
self.auto_now = auto_now
def __get_base_value__(self, user_value):
# Return server timestamp as the value
if user_value == SERVER_TIMESTAMP or self.auto_now:
return SERVER_TIMESTAMP
if user_value is None and self.default == SERVER_TIMESTAMP:
return SERVER_TIMESTAMP
return self.__type_check__(user_value, datetime)
def __get_user_value__(self, base_value):
return base_value
class DateProperty(Property):
"""A Property whose value is a date object.
Args:
default (datetime): The default value for this property
required (bool): Enforce that this property can't be submitted when empty
auto_add_now (bool): Set to the current date when a record is created
"""
def __init__(self, default=None, required=False, auto_add_now=False):
if not default and auto_add_now:
default = SERVER_TIMESTAMP
super(DateProperty, self).__init__(default=default, required=required)
def __get_base_value__(self, user_value):
# Return server timestamp as the value
if user_value is None and self.default == SERVER_TIMESTAMP:
return SERVER_TIMESTAMP
if isinstance(user_value, datetime):
return user_value.date()
return self.__type_check__(user_value, date)
def __get_user_value__(self, base_value):
if isinstance(base_value, datetime):
return base_value.date()
return base_value
class PickledProperty(Property):
"""A Property whose value is any picklable Python object."""
def __int__(self, required=False):
super(PickledProperty, self).__init__(default=None, required=required)
def __get_base_value__(self, user_value):
return pickle.dumps(user_value)
def __get_user_value__(self, base_value):
return pickle.loads(base_value)
class InvalidValueError(ValueError):
"""Raised if the value of a property does not fit the property type"""
def __init__(self, property, value):
self.property = property
self.value = value
def __str__(self):
return "%s is not a valid value for property %s of type %s" % \
(self.value, self.property.name, type(self.property).__name__)
class MalformedQueryError(Exception):
"""Raised when the rules of a query are broken"""
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
class InvalidPropertyError(Exception):
"""Raised if a non-existent property is provided during the creation of a model"""
def __init__(self, prop_name, model_name):
self.prop_name = prop_name
self.model_name = model_name
def __str__(self):
return "%s not found in model %s" % (self.prop_name, self.model_name)
class ReferencePropertyError(Exception):
"""Raised when a reference property point's to a location the model can't resolve"""
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
Classes
class BlobProperty (default=None, required=False)
-
A Property whose value is a byte string. It may be compressed.
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class BlobProperty(Property): """A Property whose value is a byte string. It may be compressed.""" def __get_base_value__(self, user_value): return self.__type_check__(user_value, (bytes, bytearray)) def __get_user_value__(self, base_value): return base_value
Ancestors
class BooleanProperty (default=None, required=False)
-
A Property whose value is a Python bool.
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class BooleanProperty(Property): """A Property whose value is a Python bool.""" def __get_base_value__(self, user_value): return self.__type_check__(user_value, bool) def __get_user_value__(self, base_value): return base_value
Ancestors
class DateProperty (default=None, required=False, auto_add_now=False)
-
A Property whose value is a date object.
Args
default
:datetime
- The default value for this property
required
:bool
- Enforce that this property can't be submitted when empty
auto_add_now
:bool
- Set to the current date when a record is created
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class DateProperty(Property): """A Property whose value is a date object. Args: default (datetime): The default value for this property required (bool): Enforce that this property can't be submitted when empty auto_add_now (bool): Set to the current date when a record is created """ def __init__(self, default=None, required=False, auto_add_now=False): if not default and auto_add_now: default = SERVER_TIMESTAMP super(DateProperty, self).__init__(default=default, required=required) def __get_base_value__(self, user_value): # Return server timestamp as the value if user_value is None and self.default == SERVER_TIMESTAMP: return SERVER_TIMESTAMP if isinstance(user_value, datetime): return user_value.date() return self.__type_check__(user_value, date) def __get_user_value__(self, base_value): if isinstance(base_value, datetime): return base_value.date() return base_value
Ancestors
class DateTimeProperty (default=None, required=False, auto_now=False, auto_add_now=False)
-
A Property whose value is a datetime object.
Note: auto_now_add can be overridden by setting the value before writing the entity.
Args
- default (datetime)
required
:bool
- Enforce that this property can't be submitted when empty
auto_now
:bool
- Set to the current time every time the model is updated
auto_add_now
:bool
- Set to the current time when a record is created
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class DateTimeProperty(Property): """A Property whose value is a datetime object. Note: auto_now_add can be overridden by setting the value before writing the entity. Args: default (datetime) required (bool): Enforce that this property can't be submitted when empty auto_now (bool): Set to the current time every time the model is updated auto_add_now (bool): Set to the current time when a record is created """ def __init__(self, default=None, required=False, auto_now=False, auto_add_now=False): if not default and auto_add_now: default = SERVER_TIMESTAMP super(DateTimeProperty, self).__init__(default=default, required=required) self.auto_now = auto_now def __get_base_value__(self, user_value): # Return server timestamp as the value if user_value == SERVER_TIMESTAMP or self.auto_now: return SERVER_TIMESTAMP if user_value is None and self.default == SERVER_TIMESTAMP: return SERVER_TIMESTAMP return self.__type_check__(user_value, datetime) def __get_user_value__(self, base_value): return base_value
Ancestors
class FloatingPointNumberProperty (default=None, required=False)
-
A Property whose value is a Python float.
Note: int and long are also allowed.
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class FloatingPointNumberProperty(Property): """A Property whose value is a Python float. Note: int and long are also allowed. """ def __get_base_value__(self, user_value: float): user_value = self.__type_check__(user_value, (int, float)) return user_value def __get_user_value__(self, base_value): return base_value
Ancestors
class IntegerProperty (default=None, required=False)
-
A Property whose value is a Python int or long
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class IntegerProperty(Property): """A Property whose value is a Python int or long""" def __get_base_value__(self, user_value): return self.__type_check__(user_value, int) def __get_user_value__(self, base_value): return base_value
Ancestors
class InvalidPropertyError (prop_name, model_name)
-
Raised if a non-existent property is provided during the creation of a model
Source code
class InvalidPropertyError(Exception): """Raised if a non-existent property is provided during the creation of a model""" def __init__(self, prop_name, model_name): self.prop_name = prop_name self.model_name = model_name def __str__(self): return "%s not found in model %s" % (self.prop_name, self.model_name)
Ancestors
- builtins.Exception
- builtins.BaseException
class InvalidValueError (property, value)
-
Raised if the value of a property does not fit the property type
Source code
class InvalidValueError(ValueError): """Raised if the value of a property does not fit the property type""" def __init__(self, property, value): self.property = property self.value = value def __str__(self): return "%s is not a valid value for property %s of type %s" % \ (self.value, self.property.name, type(self.property).__name__)
Ancestors
- builtins.ValueError
- builtins.Exception
- builtins.BaseException
class JsonProperty (required=False)
-
A property whose value is any Json-encodable Python object.
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class JsonProperty(Property): """A property whose value is any Json-encodable Python object. """ def __init__(self, required=False): super(JsonProperty, self).__init__(required=required, default={}) def __get_base_value__(self, user_value): if isinstance(user_value, str): try: user_value = json.loads(user_value) except json.JSONDecodeError: raise InvalidPropertyError(self, "Dict property must be valid JSON") return self.__type_check__(user_value, dict) def __get_user_value__(self, base_value): return base_value
Ancestors
class ListProperty (property_type)
-
A List property
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class ListProperty(Property): """A List property""" def __init__(self, property_type: Property): super(ListProperty, self).__init__(default=[]) self.property_type = property_type def __get_base_value__(self, user_value: list): user_value = self.__type_check__(user_value, (list)) user_value = [self.property_type.__get_base_value__(value) for value in user_value] return user_value def __get_user_value__(self, base_value): return base_value
Ancestors
class MalformedQueryError (message)
-
Raised when the rules of a query are broken
Source code
class MalformedQueryError(Exception): """Raised when the rules of a query are broken""" def __init__(self, message): self.message = message def __str__(self): return self.message
Ancestors
- builtins.Exception
- builtins.BaseException
class PickledProperty (default=None, required=False)
-
A Property whose value is any picklable Python object.
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class PickledProperty(Property): """A Property whose value is any picklable Python object.""" def __int__(self, required=False): super(PickledProperty, self).__init__(default=None, required=required) def __get_base_value__(self, user_value): return pickle.dumps(user_value) def __get_user_value__(self, base_value): return pickle.loads(base_value)
Ancestors
class Property (default=None, required=False)
-
A class describing a typed, persisted attribute of a database entity
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class Property(object): """ A class describing a typed, persisted attribute of a database entity """ def __init__(self, default=None, required=False): """ Args: default: The default value of the property required: Enforce the property value to be provided """ if type(self) is Property: raise Exception("You must extend Property") self.default = default self.required = required self.name = None def __get_user_value__(self, base_value): """ Convert value from database to a value usable by the user Args: base_value: The current value from db Returns: user_value expected to be of the specified type """ raise NotImplementedError def __get_base_value__(self, user_value): """ Convert value to database acceptable format Args :param user_value: Current user_value :return: base_value """ raise NotImplementedError def __type_check__(self, user_value, data_types): """ Check whether this value has the right data type Args: user_value: The user_value you want to confirm data_types: Type/Types to check against Returns: Any """ if self.required and self.default is None and user_value is None: raise InvalidValueError(self, user_value) # Assign a default value if None is provided if user_value is None: user_value = self.default if not isinstance(user_value, data_types) and user_value is not None: raise InvalidValueError(self, user_value) return user_value
Subclasses
class ReferenceProperty (entity, required=False)
-
A class describing a typed, persisted attribute of a database entity
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class ReferenceProperty(Property): def __init__(self, entity, required=False): from firestore import Entity if not issubclass(entity, Entity): raise ReferencePropertyError("A reference property must reference another model") super(ReferenceProperty, self).__init__(required=required) self.entity = entity def __get_base_value__(self, user_value): user_value = self.__type_check__(user_value, (self.entity)) if not user_value: return user_value if not user_value.id: raise ReferencePropertyError("A reference must be put first before it can be referenced") return user_value.__document__() def __get_user_value__(self, base_value): if not base_value: return None user_data = self.entity.__get_user_data__(base_value.get().to_dict()) return self.entity(id=base_value.id, **user_data)
Ancestors
class ReferencePropertyError (message)
-
Raised when a reference property point's to a location the model can't resolve
Source code
class ReferencePropertyError(Exception): """Raised when a reference property point's to a location the model can't resolve""" def __init__(self, message): self.message = message def __str__(self): return self.message
Ancestors
- builtins.Exception
- builtins.BaseException
class StringProperty (default=None, length=255, required=False)
-
An indexed Property whose value is a text string of limited length.
Args
default
- Default value for this property
length
:int
- The maximum length of this property
required
:bool
- Enforce whether this value can be empty
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class StringProperty(Property): """ An indexed Property whose value is a text string of limited length. Args: default: Default value for this property length (int): The maximum length of this property required (bool): Enforce whether this value can be empty """ def __init__(self, default=None, length=255, required=False): super(StringProperty, self).__init__(default=default, required=required) self.length = length def __get_base_value__(self, user_value): user_value = self.__type_check__(user_value, str) if user_value is not None and len(user_value) > self.length: raise InvalidValueError(self, user_value) return user_value def __get_user_value__(self, base_value): return base_value
Ancestors
class TextProperty (default=None, required=False)
-
An Property whose value is a text string of unlimited length. I'ts not advisable to index this property
Args
default
- The default value of the property
required
- Enforce the property value to be provided
Source code
class TextProperty(Property): """An Property whose value is a text string of unlimited length. I'ts not advisable to index this property """ def __get_base_value__(self, user_value): return self.__type_check__(user_value, str) def __get_user_value__(self, base_value): return base_value
Ancestors