cqle: introduce 'date' and 'time' column types

PYTHON-245
This commit is contained in:
Adam Holmberg
2015-05-19 16:27:48 -05:00
parent ccd7e460e2
commit b43a947d4a
4 changed files with 64 additions and 41 deletions

View File

@@ -19,9 +19,8 @@ import re
import six
import warnings
from cassandra.cqltypes import DateType
from cassandra.encoder import cql_quote
from cassandra import util
from cassandra.cqltypes import DateType, SimpleDateType
from cassandra.cqlengine import ValidationError
log = logging.getLogger(__name__)
@@ -361,6 +360,10 @@ class Integer(Column):
class TinyInt(Integer):
"""
Stores an 8-bit signed integer value
.. versionadded:: 2.6.0
requires C* 2.2+ and protocol v4+
"""
db_type = 'tinyint'
@@ -368,6 +371,10 @@ class TinyInt(Integer):
class SmallInt(Integer):
"""
Stores a 16-bit signed integer value
.. versionadded:: 2.6.0
requires C* 2.2+ and protocol v4+
"""
db_type = 'smallint'
@@ -466,35 +473,43 @@ class DateTime(Column):
class Date(Column):
"""
*Note: this type is overloaded, and will likely be changed or removed to accommodate distinct date type
in a future version*
Stores a simple date, with no time-of-day
Stores a date value, with no time-of-day
.. versionchanged:: 2.6.0
removed overload of Date and DateTime. DateTime is a drop-in replacement for legacy models
requires C* 2.2+ and protocol v4+
"""
db_type = 'timestamp'
def to_python(self, value):
if value is None:
return
if isinstance(value, datetime):
return value.date()
elif isinstance(value, date):
return value
try:
return datetime.utcfromtimestamp(value).date()
except TypeError:
return datetime.utcfromtimestamp(DateType.deserialize(value)).date()
db_type = 'date'
def to_database(self, value):
value = super(Date, self).to_database(value)
if value is None:
return
if isinstance(value, datetime):
value = value.date()
if not isinstance(value, date):
raise ValidationError("{} '{}' is not a date object".format(self.column_name, repr(value)))
return int((value - date(1970, 1, 1)).total_seconds() * 1000)
# need to translate to int version because some dates are not representable in
# string form (datetime limitation)
d = value if isinstance(value, util.Date) else util.Date(value)
return d.days_from_epoch + SimpleDateType.EPOCH_OFFSET_DAYS
class Time(Column):
"""
Stores a timezone-naive time-of-day, with nanosecond precision
.. versionadded:: 2.6.0
requires C* 2.2+ and protocol v4+
"""
db_type = 'time'
def to_database(self, value):
value = super(Time, self).to_database(value)
if value is None:
return
# str(util.Time) yields desired CQL encoding
return value if isinstance(value, util.Time) else util.Time(value)
class UUID(Column):
@@ -852,7 +867,7 @@ class UserDefinedType(Column):
def __init__(self, user_type, **kwargs):
"""
:param type user_type: specifies the :class:`~.UserType` model of the column
:param type user_type: specifies the :class:`~.cqlengine.usertype.UserType` model of the column
"""
self.user_type = user_type
self.db_type = "frozen<%s>" % user_type.type_name()

View File

@@ -638,27 +638,29 @@ class SimpleDateType(_CassandraType):
typename = 'date'
date_format = "%Y-%m-%d"
# Values of the 'date'` type are encoded as 32-bit unsigned integers
# representing a number of days with epoch (January 1st, 1970) at the center of the
# range (2^31).
EPOCH_OFFSET_DAYS = 2 ** 31
@classmethod
def validate(cls, val):
if not isinstance(val, util.Date):
val = util.Date(val)
return val
@staticmethod
def deserialize(byts, protocol_version):
days = uint32_unpack(byts) - SimpleDateType.EPOCH_OFFSET_DAYS
return util.Date(days)
@staticmethod
def serialize(val, protocol_version):
# Values of the 'date'` type are encoded as 32-bit unsigned integers
# representing a number of days with epoch (January 1st, 1970) at the center of the
# range (2^31).
try:
days = val.days_from_epoch
except AttributeError:
days = util.Date(val).days_from_epoch
return uint32_pack(days + 2 ** 31)
@staticmethod
def deserialize(byts, protocol_version):
days = uint32_unpack(byts) - 2 ** 31
return util.Date(days)
return uint32_pack(days + SimpleDateType.EPOCH_OFFSET_DAYS)
class ShortType(_CassandraType):
@@ -682,6 +684,10 @@ class TimeType(_CassandraType):
val = util.Time(val)
return val
@staticmethod
def deserialize(byts, protocol_version):
return util.Time(int64_unpack(byts))
@staticmethod
def serialize(val, protocol_version):
try:
@@ -690,10 +696,6 @@ class TimeType(_CassandraType):
nano = util.Time(val).nanosecond_time
return int64_pack(nano)
@staticmethod
def deserialize(byts, protocol_version):
return util.Time(int64_unpack(byts))
class UTF8Type(_CassandraType):
typename = 'text'

View File

@@ -917,7 +917,7 @@ class Time(object):
class Date(object):
'''
Idealized naive date: year, month, day
Idealized date: year, month, day
Offers wider year range than datetime.date. For Dates that cannot be represented
as a datetime.date (because datetime.MINYEAR, datetime.MAXYEAR), this type falls back
@@ -997,5 +997,5 @@ class Date(object):
dt = datetime_from_timestamp(self.seconds)
return "%04d-%02d-%02d" % (dt.year, dt.month, dt.day)
except:
# If we overflow datetime.[MIN|M
# If we overflow datetime.[MIN|MAX]
return str(self.days_from_epoch)

View File

@@ -52,7 +52,7 @@ Columns of all types are initialized by passing :class:`.Column` attributes to t
.. autoclass:: Counter
.. autoclass:: Date(**kwargs)
.. autoclass:: Date
.. autoclass:: DateTime(**kwargs)
@@ -70,10 +70,16 @@ Columns of all types are initialized by passing :class:`.Column` attributes to t
.. autoclass:: Set
.. autoclass:: SmallInt
.. autoclass:: Text
.. autoclass:: Time
.. autoclass:: TimeUUID(**kwargs)
.. autoclass:: TinyInt
.. autoclass:: UserDefinedType
.. autoclass:: UUID(**kwargs)