summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/mapping
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/mapping')
-rw-r--r--lib/sqlalchemy/mapping/mapper.py11
-rw-r--r--lib/sqlalchemy/mapping/properties.py2
-rw-r--r--lib/sqlalchemy/mapping/util.py73
3 files changed, 80 insertions, 6 deletions
diff --git a/lib/sqlalchemy/mapping/mapper.py b/lib/sqlalchemy/mapping/mapper.py
index a0de86df4..f8faea855 100644
--- a/lib/sqlalchemy/mapping/mapper.py
+++ b/lib/sqlalchemy/mapping/mapper.py
@@ -9,6 +9,7 @@ import sqlalchemy.sql as sql
import sqlalchemy.schema as schema
import sqlalchemy.engine as engine
import sqlalchemy.util as util
+import util as mapperutil
import sync
from sqlalchemy.exceptions import *
import objectstore
@@ -419,7 +420,7 @@ class Mapper(object):
e.g. result = usermapper.select_by(user_name = 'fred')
"""
- return self.select_whereclause(self._by_clause(*args, **params))
+ return mapperutil.SelectResults(self, self._by_clause(*args, **params))
def selectfirst_by(self, *args, **params):
"""works like select_by(), but only returns the first result by itself, or None if no
@@ -428,7 +429,7 @@ class Mapper(object):
def selectone_by(self, *args, **params):
"""works like selectfirst_by(), but throws an error if not exactly one result was returned."""
- ret = self.select_by(*args, **params)
+ ret = list(self.select_by(*args, **params)[0:2])
if len(ret) == 1:
return ret[0]
raise InvalidRequestError('Multiple rows returned for selectone_by')
@@ -491,7 +492,7 @@ class Mapper(object):
"""works like select(), but only returns the first result by itself, or None if no
objects returned."""
params['limit'] = 1
- ret = self.select(*args, **params)
+ ret = self.select_whereclause(*args, **params)
if ret:
return ret[0]
else:
@@ -499,7 +500,7 @@ class Mapper(object):
def selectone(self, *args, **params):
"""works like selectfirst(), but throws an error if not exactly one result was returned."""
- ret = self.select(*args, **params)
+ ret = list(self.select(*args, **params)[0:2])
if len(ret) == 1:
return ret[0]
raise InvalidRequestError('Multiple rows returned for selectone')
@@ -517,7 +518,7 @@ class Mapper(object):
if arg is not None and isinstance(arg, sql.Selectable):
return self.select_statement(arg, **kwargs)
else:
- return self.select_whereclause(arg, **kwargs)
+ return mapperutil.SelectResults(self, arg, ops=kwargs)
def select_whereclause(self, whereclause=None, params=None, **kwargs):
statement = self._compile(whereclause, **kwargs)
diff --git a/lib/sqlalchemy/mapping/properties.py b/lib/sqlalchemy/mapping/properties.py
index b18d4d54f..206905aa4 100644
--- a/lib/sqlalchemy/mapping/properties.py
+++ b/lib/sqlalchemy/mapping/properties.py
@@ -616,7 +616,7 @@ class LazyLoader(PropertyLoader):
order_by = self.secondary.default_order_by()
else:
order_by = False
- result = self.mapper.select(self.lazywhere, order_by=order_by, params=params)
+ result = list(self.mapper.select(self.lazywhere, order_by=order_by, params=params))
else:
result = []
if self.uselist:
diff --git a/lib/sqlalchemy/mapping/util.py b/lib/sqlalchemy/mapping/util.py
new file mode 100644
index 000000000..74b6c7557
--- /dev/null
+++ b/lib/sqlalchemy/mapping/util.py
@@ -0,0 +1,73 @@
+from sqlalchemy.sql import and_, select, func
+
+class SelectResults(object):
+ def __init__(self, mapper, clause=None, ops={}):
+ self._mapper = mapper
+ self._clause = clause
+ self._ops = {}
+ self._ops.update(ops)
+
+ def count(self):
+ return self._mapper.count(self._clause)
+
+ def __len__(self):
+ return self.count()
+
+ def min(self, col):
+ return select([func.min(col)], self._clause, **self._ops).scalar()
+
+ def max(self, col):
+ return select([func.max(col)], self._clause, **self._ops).scalar()
+
+ def sum(self, col):
+ return select([func.sum(col)], self._clause, **self._ops).scalar()
+
+ def avg(self, col):
+ return select([func.avg(col)], self._clause, **self._ops).scalar()
+
+ def clone(self):
+ return SelectResults(self._mapper, self._clause, self._ops.copy())
+
+ def filter(self, clause):
+ new = self.clone()
+ new._clause = and_(self._clause, clause)
+ return new
+
+ def order_by(self, order_by):
+ new = self.clone()
+ new._ops['order_by'] = order_by
+ return new
+
+ def limit(self, limit):
+ return self[:limit]
+
+ def offset(self, offset):
+ return self[offset:]
+
+ def list(self):
+ return list(self)
+
+ def __getitem__(self, item):
+ if isinstance(item, slice):
+ start = item.start
+ stop = item.stop
+ if (isinstance(start, int) and start < 0) or \
+ (isinstance(stop, int) and stop < 0):
+ return list(self)[item]
+ else:
+ res = self.clone()
+ if start is not None and stop is not None:
+ res._ops.update(dict(offset=start, limit=stop-start))
+ elif start is None and stop is not None:
+ res._ops.update(dict(limit=stop))
+ elif start is not None and stop is None:
+ res._ops.update(dict(offset=start))
+ if item.step is not None:
+ return list(res)[None:None:item.step]
+ else:
+ return res
+ else:
+ return list(self[item:item+1])[0]
+
+ def __iter__(self):
+ return iter(self._mapper.select_whereclause(self._clause, **self._ops)) \ No newline at end of file