Author: phd
Date: 2005-11-03 12:15:48 +0000 (Thu, 03 Nov 2005)
New Revision: 1202
Added:
home/phd/SQLObject/paramstyles/sqlobject/tests/test_events.py
Modified:
home/phd/SQLObject/paramstyles/docs/News.txt
home/phd/SQLObject/paramstyles/sqlobject/events.py
home/phd/SQLObject/paramstyles/sqlobject/main.py
home/phd/SQLObject/paramstyles/sqlobject/sresults.py
home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py
Log:
Merged patches from the revisions 1196:1201 from the trunk
Modified: home/phd/SQLObject/paramstyles/docs/News.txt
===================================================================
--- home/phd/SQLObject/paramstyles/docs/News.txt 2005-11-03 08:17:07 UTC (rev 1201)
+++ home/phd/SQLObject/paramstyles/docs/News.txt 2005-11-03 12:15:48 UTC (rev 1202)
@@ -43,6 +43,13 @@
This will run ``process_request(os.environ)``. The return
value will be preserved.
+* Added method ``.getOne([default])`` to ``SelectResults`` (these are
+ the objects returned by ``.select()`` and ``.selectBy()``). This
+ returns a single object, when the query is expected to return only
+ one object. The single argument is the value to return when zero
+ results are found (more than one result is always an error). If no
+ default is given, it is an error if no such object exists.
+
SQLObject 0.7.1
===============
Modified: home/phd/SQLObject/paramstyles/sqlobject/events.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/events.py 2005-11-03 08:17:07 UTC (rev 1201)
+++ home/phd/SQLObject/paramstyles/sqlobject/events.py 2005-11-03 12:15:48 UTC (rev 1202)
@@ -14,9 +14,8 @@
an event is fired on any subclass.
"""
dispatcher.connect(receiver, signal=signal, sender=soClass)
- weakSOClass = ref(soClass)
weakReceiver = ref(receiver)
- subclassClones.setdefault(weakSOClass, []).append((weakReceiver, signal))
+ subclassClones.setdefault(soClass, []).append((weakReceiver, signal))
# We export this function:
send = dispatcher.send
@@ -53,7 +52,7 @@
receiver = weakReceiver()
if not receiver:
continue
- dispatcher.connect(receiver, signal=signal, sender=new_class)
+ listen(receiver, new_class, signal)
dispatcher.connect(_makeSubclassConnections, signal=ClassCreateSignal)
Modified: home/phd/SQLObject/paramstyles/sqlobject/main.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/main.py 2005-11-03 08:17:07 UTC (rev 1201)
+++ home/phd/SQLObject/paramstyles/sqlobject/main.py 2005-11-03 12:15:48 UTC (rev 1202)
@@ -297,6 +297,7 @@
def addColumn(cls, columnDef, changeSchema=False, connection=None):
post_funcs = []
+ print "Send on", cls.soClass, columnDef.name
cls.send(events.AddColumnSignal, cls.soClass, connection,
columnDef.name, columnDef, changeSchema, post_funcs)
sqlmeta = cls
@@ -1060,7 +1061,8 @@
# the parts are set. So we just keep them in a
# dictionary until later:
d = {name: value}
- self.sqlmeta.send(events.RowUpdateSignal, self, d)
+ if not self.sqlmeta._creating:
+ self.sqlmeta.send(events.RowUpdateSignal, self, d)
if len(d) != 1 or name not in d:
return self.set(**d)
value = d[name]
@@ -1084,7 +1086,8 @@
setattr(self, instanceName(name), value)
def set(self, **kw):
- self.sqlmeta.send(events.RowUpdateSignal, self, kw)
+ if not self.sqlmeta._creating:
+ self.sqlmeta.send(events.RowUpdateSignal, self, kw)
# set() is used to update multiple values at once,
# potentially with one SQL statement if possible.
Modified: home/phd/SQLObject/paramstyles/sqlobject/sresults.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/sresults.py 2005-11-03 08:17:07 UTC (rev 1201)
+++ home/phd/SQLObject/paramstyles/sqlobject/sresults.py 2005-11-03 12:15:48 UTC (rev 1202)
@@ -1,5 +1,6 @@
import sqlbuilder
import dbconnection
+import main
StringType = type('')
@@ -227,4 +228,29 @@
def max(self, attribute):
return self.accumulateOne("MAX", attribute)
+ def getOne(self, default=sqlbuilder.NoDefault):
+ """
+ If a query is expected to only return a single value,
+ using ``.getOne()`` will return just that value.
+
+ If not results are found, ``SQLObjectNotFound`` will be
+ raised, unless you pass in a default value (like
+ ``.getOne(None)``).
+
+ If more than one result is returned,
+ ``SQLObjectIntegrityError`` will be raised.
+ """
+ results = list(self)
+ if not results:
+ if default is sqlbuilder.NoDefault:
+ raise main.SQLObjectNotFound(
+ "No results matched the query for %s"
+ % self.sourceClass.__name__)
+ return default
+ if len(results) > 1:
+ raise main.SQLObjectIntegrityError(
+ "More than one result returned from query: %s"
+ % results)
+ return results[0]
+
__all__ = ['SelectResults']
Copied: home/phd/SQLObject/paramstyles/sqlobject/tests/test_events.py (from rev 1201, SQLObject/trunk/sqlobject/tests/test_events.py)
Modified: home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py 2005-11-03 08:17:07 UTC (rev 1201)
+++ home/phd/SQLObject/paramstyles/sqlobject/tests/test_select.py 2005-11-03 12:15:48 UTC (rev 1202)
@@ -1,6 +1,8 @@
from __future__ import generators # for enumerate
from sqlobject import *
+from sqlobject.main import SQLObjectIntegrityError
from sqlobject.tests.dbtest import *
+from py.test import raises
try:
enumerate
@@ -71,6 +73,18 @@
pass
assert count == len(names)
+def test_select_getOne():
+ setupClass(IterTest)
+ a = IterTest(name='a')
+ b = IterTest(name='b')
+ assert IterTest.selectBy(name='a').getOne() == a
+ assert IterTest.select(IterTest.q.name=='b').getOne() == b
+ assert IterTest.selectBy(name='c').getOne(None) is None
+ raises(SQLObjectNotFound, 'IterTest.selectBy(name="c").getOne()')
+ b2 = IterTest(name='b')
+ raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne()')
+ raises(SQLObjectIntegrityError, 'IterTest.selectBy(name="b").getOne(None)')
+
|