diff options
Diffstat (limited to 'lib/sqlalchemy/mapping')
-rw-r--r-- | lib/sqlalchemy/mapping/mapper.py | 11 | ||||
-rw-r--r-- | lib/sqlalchemy/mapping/properties.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/mapping/util.py | 73 |
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 |