Skip to content

Commit

Permalink
PostgreSQL support. Fix #1.
Browse files Browse the repository at this point in the history
  • Loading branch information
kmike committed Jun 24, 2011
1 parent bef1539 commit 66bfbf7
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 7 deletions.
1 change: 1 addition & 0 deletions .hgignore
Expand Up @@ -27,3 +27,4 @@ build/
dist/
.build/
MANIFEST
django_qsstats_magic.egg-info
24 changes: 19 additions & 5 deletions qsstats/__init__.py
Expand Up @@ -24,6 +24,18 @@ def __init__(self, qs=None, date_field=None, aggregate=None, today=None):
self.aggregate = aggregate or Count('id')
self.today = today or self.update_today()

def _guess_engine(self):
if hasattr(self.qs, 'db'): # django 1.2+
engine_name = settings.DATABASES[self.qs.db]['ENGINE']
else:
engine_name = settings.DATABASE_ENGINE
if 'mysql' in engine_name:
return 'mysql'
if 'postg' in engine_name: #postgres, postgis
return 'postgresql'
if 'sqlite' in engine_name:
return 'sqlite'

# Aggregates for a specific period of time

def for_interval(self, interval, dt, date_field=None, aggregate=None):
Expand All @@ -44,15 +56,14 @@ def __getattr__(self, name):
return partial(self.this_interval, name[5:])
raise AttributeError


def time_series(self, start, end=None, interval='days',
date_field=None, aggregate=None, engine='mysql'):
date_field=None, aggregate=None, engine=None):
''' Aggregate over time intervals '''
end = end or self.today
args = [start, end, interval, date_field, aggregate]
engine = engine or self._guess_engine()
sid = transaction.savepoint()
try:
#TODO: engine should be guessed
return self._fast_time_series(*(args+[engine]))
except (QuerySetStatsError, DatabaseError,):
transaction.savepoint_rollback(sid)
Expand All @@ -75,10 +86,11 @@ def _slow_time_series(self, start, end, interval='days',
return stat_list

def _fast_time_series(self, start, end, interval='days',
date_field=None, aggregate=None, engine='mysql'):
date_field=None, aggregate=None, engine=None):
''' Aggregate over time intervals using just 1 sql query '''
date_field = date_field or self.date_field
aggregate = aggregate or self.aggregate
engine = engine or self._guess_engine()

start, _ = get_bounds(start, interval.rstrip('s'))
_, end = get_bounds(end, interval.rstrip('s'))
Expand All @@ -89,7 +101,9 @@ def _fast_time_series(self, start, end, interval='days',
filter(**kwargs).order_by().values('d').\
annotate(agg=aggregate)

data = dict((parse(item['d'], yearfirst=True), item['agg']) for item in aggregate_data)
def to_dt(d): # leave dates as-is
return parse(d, yearfirst=True) if isinstance(d, basestring) else d
data = dict((to_dt(item['d']), item['agg']) for item in aggregate_data)

stat_list = []
dt = start
Expand Down
11 changes: 10 additions & 1 deletion qsstats/utils.py
Expand Up @@ -53,13 +53,22 @@ def get_interval_sql(date_field, interval, engine):
'weeks': "DATE_FORMAT(DATE_SUB(`"+date_field+"`, INTERVAL(WEEKDAY(`"+date_field+"`)) DAY), '%%Y-%%m-%%d')",
'months': "DATE_FORMAT(`" + date_field +"`, '%%Y-%%m-01')",
'years': "DATE_FORMAT(`" + date_field +"`, '%%Y-01-01')",
},
'postgresql': {
'minutes': "date_trunc('minute', %s)" % date_field,
'hours': "date_trunc('hour', %s)" % date_field,
'days': "date_trunc('day', %s)" % date_field,
'weeks': "date_trunc('week', %s)" % date_field,
'months': "date_trunc('month', %s)" % date_field,
'years': "date_trunc('year', %s)" % date_field,
}
}

try:
engine_sql = SQL[engine]
except KeyError:
raise UnsupportedEngine('%s DB engine is not supported' % engine)
msg = '%s DB engine is not supported. Supported engines are: %s' % (engine, ", ".join(SQL.keys()))
raise UnsupportedEngine(msg)

try:
return engine_sql[interval]
Expand Down
10 changes: 9 additions & 1 deletion runtests.py
Expand Up @@ -3,10 +3,18 @@

from django.conf import settings
from django.core.management import call_command
import sys

engine = sys.argv[1]

settings.configure(
INSTALLED_APPS=('qsstats', 'django.contrib.auth', 'django.contrib.contenttypes'),
DATABASE_ENGINE = 'sqlite3',
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.' + engine,
'NAME': 'test'
}
}
)

if __name__ == "__main__":
Expand Down
5 changes: 5 additions & 0 deletions setup.py
@@ -1,6 +1,11 @@
#!/usr/bin/env python
from distutils.core import setup

for cmd in ('egg_info', 'develop'):
import sys
if cmd in sys.argv:
from setuptools import setup

setup(
name='django-qsstats-magic',
version='0.5.2',
Expand Down

0 comments on commit 66bfbf7

Please sign in to comment.