summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/dialects/sqlite/base.py
diff options
context:
space:
mode:
authorGaëtan de Menten <gdementen@gmail.com>2009-11-17 18:35:06 +0000
committerGaëtan de Menten <gdementen@gmail.com>2009-11-17 18:35:06 +0000
commit1bca0c42a3f4626f0273e61cf1b59ece37c3bd26 (patch)
tree43f62bb857eb9fbd9824ff50a466b7c36f30ed6b /lib/sqlalchemy/dialects/sqlite/base.py
parentf96130aceffd4f69dd5ce4a1afaddd6f7f209cf7 (diff)
downloadsqlalchemy-1bca0c42a3f4626f0273e61cf1b59ece37c3bd26.tar.gz
- sqlite
- DATE, TIME and DATETIME types can now take optional storage_format and regexp argument. storage_format can be used to store those types using a custom string format. regexp allows to use a custom regular expression to match string values from the database. - Time and DateTime types now use by a default a stricter regular expression to match strings from the database. Use the regexp argument if you are using data stored in a legacy format. - __legacy_microseconds__ on SQLite Time and DateTime types is not supported anymore. You should use the storage_format argument instead. - Date, Time and DateTime types are now stricter in what they accept as bind parameters: Date type only accepts date objects (and datetime ones, because they inherit from date), Time only accepts time objects, and DateTime only accepts date and datetime objects.
Diffstat (limited to 'lib/sqlalchemy/dialects/sqlite/base.py')
-rw-r--r--lib/sqlalchemy/dialects/sqlite/base.py126
1 files changed, 71 insertions, 55 deletions
diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py
index 33feaeaae..17619d2b5 100644
--- a/lib/sqlalchemy/dialects/sqlite/base.py
+++ b/lib/sqlalchemy/dialects/sqlite/base.py
@@ -15,7 +15,7 @@ SQLite does not have built-in DATE, TIME, or DATETIME types, and pysqlite does n
out of the box functionality for translating values between Python `datetime` objects
and a SQLite-supported format. SQLAlchemy's own :class:`~sqlalchemy.types.DateTime`
and related types provide date formatting and parsing functionality when SQlite is used.
-The implementation classes are :class:`_SLDateTime`, :class:`_SLDate` and :class:`_SLTime`.
+The implementation classes are :class:`DATETIME`, :class:`DATE` and :class:`TIME`.
These types represent dates and times as ISO formatted strings, which also nicely
support ordering. There's no reliance on typical "libc" internals for these functions
so historical dates are fully supported.
@@ -59,76 +59,92 @@ class _SLFloat(_NumericMixin, sqltypes.Float):
# or JDBC would similarly have no built in date support, so the "string" based logic
# would apply to all implementing dialects.
class _DateTimeMixin(object):
- def _bind_processor(self, format, elements):
- def process(value):
- if not isinstance(value, (NoneType, datetime.date, datetime.datetime, datetime.time)):
- raise TypeError("SQLite Date, Time, and DateTime types only accept Python datetime objects as input.")
- elif value is not None:
- return format % tuple([getattr(value, attr, 0) for attr in elements])
- else:
- return None
- return process
+ _reg = None
+ _storage_format = None
- def _result_processor(self, fn, regexp):
- rmatch = regexp.match
+ def __init__(self, storage_format=None, regexp=None, **kwargs):
+ if regexp is not None:
+ self._reg = re.compile(regexp)
+ if storage_format is not None:
+ self._storage_format = storage_format
+
+ def _result_processor(self, fn):
+ rmatch = self._reg.match
# Even on python2.6 datetime.strptime is both slower than this code
# and it does not support microseconds.
def process(value):
if value is not None:
- return fn(*[int(x or 0) for x in rmatch(value).groups()])
+ return fn(*map(int, rmatch(value).groups(0)))
else:
return None
return process
-class _SLDateTime(_DateTimeMixin, sqltypes.DateTime):
- __legacy_microseconds__ = False
-
+class DATETIME(_DateTimeMixin, sqltypes.DateTime):
+ _reg = re.compile(r"(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)\.(\d+)")
+ _storage_format = "%04d-%02d-%02d %02d:%02d:%02d.%06d"
+
def bind_processor(self, dialect):
- if self.__legacy_microseconds__:
- return self._bind_processor(
- "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d.%s",
- ("year", "month", "day", "hour", "minute", "second", "microsecond")
- )
- else:
- return self._bind_processor(
- "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d.%06d",
- ("year", "month", "day", "hour", "minute", "second", "microsecond")
- )
+ datetime_datetime = datetime.datetime
+ datetime_date = datetime.date
+ format = self._storage_format
+ def process(value):
+ if value is None:
+ return None
+ elif isinstance(value, datetime_datetime):
+ return format % (value.year, value.month, value.day,
+ value.hour, value.minute, value.second,
+ value.microsecond)
+ elif isinstance(value, datetime_date):
+ return format % (value.year, value.month, value.day,
+ 0, 0, 0, 0)
+ else:
+ raise TypeError("SQLite DateTime type only accepts Python "
+ "datetime and date objects as input.")
+ return process
- _reg = re.compile(r"(\d+)-(\d+)-(\d+)(?: (\d+):(\d+):(\d+)(?:\.(\d+))?)?")
def result_processor(self, dialect, coltype):
- return self._result_processor(datetime.datetime, self._reg)
-
-class _SLDate(_DateTimeMixin, sqltypes.Date):
- def bind_processor(self, dialect):
- return self._bind_processor(
- "%4.4d-%2.2d-%2.2d",
- ("year", "month", "day")
- )
+ return self._result_processor(datetime.datetime)
+class DATE(_DateTimeMixin, sqltypes.Date):
_reg = re.compile(r"(\d+)-(\d+)-(\d+)")
+ _storage_format = "%04d-%02d-%02d"
+
+ def bind_processor(self, dialect):
+ datetime_date = datetime.date
+ format = self._storage_format
+ def process(value):
+ if value is None:
+ return None
+ elif isinstance(value, datetime_date):
+ return format % (value.year, value.month, value.day)
+ else:
+ raise TypeError("SQLite Date type only accepts Python "
+ "date objects as input.")
+ return process
+
def result_processor(self, dialect, coltype):
- return self._result_processor(datetime.date, self._reg)
+ return self._result_processor(datetime.date)
-class _SLTime(_DateTimeMixin, sqltypes.Time):
- __legacy_microseconds__ = False
+class TIME(_DateTimeMixin, sqltypes.Time):
+ _reg = re.compile(r"(\d+):(\d+):(\d+)\.(\d+)")
+ _storage_format = "%02d:%02d:%02d.%06d"
def bind_processor(self, dialect):
- if self.__legacy_microseconds__:
- return self._bind_processor(
- "%2.2d:%2.2d:%2.2d.%s",
- ("hour", "minute", "second", "microsecond")
- )
- else:
- return self._bind_processor(
- "%2.2d:%2.2d:%2.2d.%06d",
- ("hour", "minute", "second", "microsecond")
- )
-
- _reg = re.compile(r"(\d+):(\d+):(\d+)(?:\.(\d+))?")
+ datetime_time = datetime.time
+ format = self._storage_format
+ def process(value):
+ if value is None:
+ return None
+ elif isinstance(value, datetime_time):
+ return format % (value.hour, value.minute, value.second,
+ value.microsecond)
+ else:
+ raise TypeError("SQLite Time type only accepts Python "
+ "time objects as input.")
+ return process
+
def result_processor(self, dialect, coltype):
- return self._result_processor(datetime.time, self._reg)
-
+ return self._result_processor(datetime.time)
class _SLBoolean(sqltypes.Boolean):
def bind_processor(self, dialect):
@@ -147,11 +163,11 @@ class _SLBoolean(sqltypes.Boolean):
colspecs = {
sqltypes.Boolean: _SLBoolean,
- sqltypes.Date: _SLDate,
- sqltypes.DateTime: _SLDateTime,
+ sqltypes.Date: DATE,
+ sqltypes.DateTime: DATETIME,
sqltypes.Float: _SLFloat,
sqltypes.Numeric: _SLNumeric,
- sqltypes.Time: _SLTime,
+ sqltypes.Time: TIME,
}
ischema_names = {