[Sqlalchemy-commits] [1225] sqlalchemy/trunk/test: Jonas Borgstr?\195?\182m's fantastic SelectRsults
Brought to you by:
zzzeek
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1225] sqlalchemy/trunk/test: Jonas Borgstr?\195?\182m's fantastic SelectRsults patch that adds dynamic list argument support to the mapper.select() methd.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1225</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-30 20:25:59 -0600 (Thu, 30 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>Jonas Borgstr?\195?\182m's fantastic SelectRsults patch that adds dynamic list argument support to the mapper.select() methd. associated unit test tweaks and mapper integration.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingmapperpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> <li><a href="#sqlalchemytrunktestalltestspy">sqlalchemy/trunk/test/alltests.py</a></li> <li><a href="#sqlalchemytrunktestmapperpy">sqlalchemy/trunk/test/mapper.py</a></li> <li><a href="#sqlalchemytrunktestproxy_enginepy">sqlalchemy/trunk/test/proxy_engine.py</a></li> <li><a href="#sqlalchemytrunktesttestbasepy">sqlalchemy/trunk/test/testbase.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingutilpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/util.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1224 => 1225)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-28 03:07:50 UTC (rev 1224) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-31 02:25:59 UTC (rev 1225) </span><span class="lines">@@ -9,6 +9,7 @@ </span><span class="cx"> import sqlalchemy.schema as schema </span><span class="cx"> import sqlalchemy.engine as engine </span><span class="cx"> import sqlalchemy.util as util </span><ins>+import util as mapperutil </ins><span class="cx"> import sync </span><span class="cx"> from sqlalchemy.exceptions import * </span><span class="cx"> import objectstore </span><span class="lines">@@ -419,7 +420,7 @@ </span><span class="cx"> </span><span class="cx"> e.g. result = usermapper.select_by(user_name = 'fred') </span><span class="cx"> """ </span><del>- return self.select_whereclause(self._by_clause(*args, **params)) </del><ins>+ return mapperutil.SelectResults(self, self._by_clause(*args, **params)) </ins><span class="cx"> </span><span class="cx"> def selectfirst_by(self, *args, **params): </span><span class="cx"> """works like select_by(), but only returns the first result by itself, or None if no </span><span class="lines">@@ -428,7 +429,7 @@ </span><span class="cx"> </span><span class="cx"> def selectone_by(self, *args, **params): </span><span class="cx"> """works like selectfirst_by(), but throws an error if not exactly one result was returned.""" </span><del>- ret = self.select_by(*args, **params) </del><ins>+ ret = list(self.select_by(*args, **params)[0:2]) </ins><span class="cx"> if len(ret) == 1: </span><span class="cx"> return ret[0] </span><span class="cx"> raise InvalidRequestError('Multiple rows returned for selectone_by') </span><span class="lines">@@ -491,7 +492,7 @@ </span><span class="cx"> """works like select(), but only returns the first result by itself, or None if no </span><span class="cx"> objects returned.""" </span><span class="cx"> params['limit'] = 1 </span><del>- ret = self.select(*args, **params) </del><ins>+ ret = self.select_whereclause(*args, **params) </ins><span class="cx"> if ret: </span><span class="cx"> return ret[0] </span><span class="cx"> else: </span><span class="lines">@@ -499,7 +500,7 @@ </span><span class="cx"> </span><span class="cx"> def selectone(self, *args, **params): </span><span class="cx"> """works like selectfirst(), but throws an error if not exactly one result was returned.""" </span><del>- ret = self.select(*args, **params) </del><ins>+ ret = list(self.select(*args, **params)[0:2]) </ins><span class="cx"> if len(ret) == 1: </span><span class="cx"> return ret[0] </span><span class="cx"> raise InvalidRequestError('Multiple rows returned for selectone') </span><span class="lines">@@ -517,7 +518,7 @@ </span><span class="cx"> if arg is not None and isinstance(arg, sql.Selectable): </span><span class="cx"> return self.select_statement(arg, **kwargs) </span><span class="cx"> else: </span><del>- return self.select_whereclause(arg, **kwargs) </del><ins>+ return mapperutil.SelectResults(self, arg, ops=kwargs) </ins><span class="cx"> </span><span class="cx"> def select_whereclause(self, whereclause=None, params=None, **kwargs): </span><span class="cx"> statement = self._compile(whereclause, **kwargs) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1224 => 1225)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-28 03:07:50 UTC (rev 1224) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-31 02:25:59 UTC (rev 1225) </span><span class="lines">@@ -616,7 +616,7 @@ </span><span class="cx"> order_by = self.secondary.default_order_by() </span><span class="cx"> else: </span><span class="cx"> order_by = False </span><del>- result = self.mapper.select(self.lazywhere, order_by=order_by, params=params) </del><ins>+ result = list(self.mapper.select(self.lazywhere, order_by=order_by, params=params)) </ins><span class="cx"> else: </span><span class="cx"> result = [] </span><span class="cx"> if self.uselist: </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingutilpy"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/lib/sqlalchemy/mapping/util.py (1224 => 1225)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/util.py 2006-03-28 03:07:50 UTC (rev 1224) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/util.py 2006-03-31 02:25:59 UTC (rev 1225) </span><span class="lines">@@ -0,0 +1,73 @@ </span><ins>+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)) </ins><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemytrunktestalltestspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/alltests.py (1224 => 1225)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/alltests.py 2006-03-28 03:07:50 UTC (rev 1224) +++ sqlalchemy/trunk/test/alltests.py 2006-03-31 02:25:59 UTC (rev 1225) </span><span class="lines">@@ -33,6 +33,7 @@ </span><span class="cx"> </span><span class="cx"> # ORM selecting </span><span class="cx"> 'mapper', </span><ins>+ 'selectresults', </ins><span class="cx"> 'eagertest1', </span><span class="cx"> 'eagertest2', </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/mapper.py (1224 => 1225)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/mapper.py 2006-03-28 03:07:50 UTC (rev 1224) +++ sqlalchemy/trunk/test/mapper.py 2006-03-31 02:25:59 UTC (rev 1225) </span><span class="lines">@@ -133,7 +133,7 @@ </span><span class="cx"> # object isnt refreshed yet, using dict to bypass trigger </span><span class="cx"> self.assert_(u.__dict__['user_name'] != 'jack') </span><span class="cx"> # do a select </span><del>- m.select() </del><ins>+ m.select().list() </ins><span class="cx"> # test that it refreshed </span><span class="cx"> self.assert_(u.__dict__['user_name'] == 'jack') </span><span class="cx"> </span><span class="lines">@@ -255,7 +255,7 @@ </span><span class="cx"> m = mapper(User, users, properties = dict( </span><span class="cx"> addresses = relation(mapper(Address, addresses), lazy = True) </span><span class="cx"> )) </span><del>- l = m.options(eagerload('addresses')).select() </del><ins>+ l = m.options(eagerload('addresses')).select().list() </ins><span class="cx"> </span><span class="cx"> def go(): </span><span class="cx"> self.assert_result(l, User, *user_address_result) </span><span class="lines">@@ -266,7 +266,7 @@ </span><span class="cx"> m = mapper(User, users, properties = dict( </span><span class="cx"> addresses = relation(mapper(Address, addresses), lazy = False) </span><span class="cx"> )) </span><del>- l = m.options(lazyload('addresses')).select() </del><ins>+ l = m.options(lazyload('addresses')).select().list() </ins><span class="cx"> def go(): </span><span class="cx"> self.assert_result(l, User, *user_address_result) </span><span class="cx"> self.assert_sql_count(db, go, 3) </span><span class="lines">@@ -282,12 +282,12 @@ </span><span class="cx"> }) </span><span class="cx"> </span><span class="cx"> m2 = m.options(eagerload('orders.items.keywords')) </span><del>- u = m.select() </del><ins>+ u = m.select().list() </ins><span class="cx"> def go(): </span><span class="cx"> print u[0].orders[1].items[0].keywords[1] </span><span class="cx"> self.assert_sql_count(db, go, 3) </span><span class="cx"> objectstore.clear() </span><del>- u = m2.select() </del><ins>+ u = m2.select().list() </ins><span class="cx"> self.assert_sql_count(db, go, 2) </span><span class="cx"> </span><span class="cx"> class PropertyTest(MapperSuperTest): </span><span class="lines">@@ -368,7 +368,7 @@ </span><span class="cx"> self.assert_(o.description is None) </span><span class="cx"> </span><span class="cx"> def go(): </span><del>- l = m.select() </del><ins>+ l = m.select().list() </ins><span class="cx"> o2 = l[2] </span><span class="cx"> print o2.description </span><span class="cx"> </span><span class="lines">@@ -397,7 +397,7 @@ </span><span class="cx"> }) </span><span class="cx"> </span><span class="cx"> def go(): </span><del>- l = m.select() </del><ins>+ l = m.select().list() </ins><span class="cx"> o2 = l[2] </span><span class="cx"> print o2.opened, o2.description, o2.userident </span><span class="cx"> self.assert_sql(db, go, [ </span><span class="lines">@@ -410,7 +410,7 @@ </span><span class="cx"> m = mapper(Order, orders) </span><span class="cx"> m2 = m.options(defer('user_id')) </span><span class="cx"> def go(): </span><del>- l = m2.select() </del><ins>+ l = m2.select().list() </ins><span class="cx"> print l[2].user_id </span><span class="cx"> self.assert_sql(db, go, [ </span><span class="cx"> ("SELECT orders.order_id AS orders_order_id, orders.description AS orders_description, orders.isopen AS orders_isopen FROM orders ORDER BY orders.%s" % orders.default_order_by()[0].key, {}), </span><span class="lines">@@ -419,7 +419,7 @@ </span><span class="cx"> objectstore.clear() </span><span class="cx"> m3 = m2.options(undefer('user_id')) </span><span class="cx"> def go(): </span><del>- l = m3.select() </del><ins>+ l = m3.select().list() </ins><span class="cx"> print l[3].user_id </span><span class="cx"> self.assert_sql(db, go, [ </span><span class="cx"> ("SELECT orders.order_id AS orders_order_id, orders.user_id AS orders_user_id, orders.description AS orders_description, orders.isopen AS orders_isopen FROM orders ORDER BY orders.%s" % orders.default_order_by()[0].key, {}), </span></span></pre></div> <a id="sqlalchemytrunktestproxy_enginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/proxy_engine.py (1224 => 1225)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/proxy_engine.py 2006-03-28 03:07:50 UTC (rev 1224) +++ sqlalchemy/trunk/test/proxy_engine.py 2006-03-31 02:25:59 UTC (rev 1225) </span><span class="lines">@@ -96,7 +96,7 @@ </span><span class="cx"> try: </span><span class="cx"> trans = objectstore.begin() </span><span class="cx"> </span><del>- all = User.select()[:] </del><ins>+ all = User.select()[:].list() </ins><span class="cx"> assert all == [] </span><span class="cx"> </span><span class="cx"> u = User() </span></span></pre></div> <a id="sqlalchemytrunktesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/testbase.py (1224 => 1225)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/testbase.py 2006-03-28 03:07:50 UTC (rev 1224) +++ sqlalchemy/trunk/test/testbase.py 2006-03-31 02:25:59 UTC (rev 1225) </span><span class="lines">@@ -74,6 +74,7 @@ </span><span class="cx"> """given a list-based structure of keys/properties which represent information within an object structure, and </span><span class="cx"> a list of actual objects, asserts that the list of objects corresponds to the structure.""" </span><span class="cx"> def assert_result(self, result, class_, *objects): </span><ins>+ result = list(result) </ins><span class="cx"> if echo: </span><span class="cx"> print repr(result) </span><span class="cx"> self.assert_list(result, class_, objects) </span></span></pre> </div> </div> </body> </html> |