sqlobject-cvs Mailing List for SQLObject (Page 175)
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
You can subscribe to this list here.
| 2003 |
Jan
|
Feb
|
Mar
(9) |
Apr
(74) |
May
(29) |
Jun
(16) |
Jul
(28) |
Aug
(10) |
Sep
(57) |
Oct
(9) |
Nov
(29) |
Dec
(12) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2004 |
Jan
(7) |
Feb
(14) |
Mar
(6) |
Apr
(3) |
May
(12) |
Jun
(34) |
Jul
(9) |
Aug
(29) |
Sep
(22) |
Oct
(2) |
Nov
(15) |
Dec
(52) |
| 2005 |
Jan
(47) |
Feb
(78) |
Mar
(14) |
Apr
(35) |
May
(33) |
Jun
(16) |
Jul
(26) |
Aug
(63) |
Sep
(40) |
Oct
(96) |
Nov
(96) |
Dec
(123) |
| 2006 |
Jan
(159) |
Feb
(144) |
Mar
(64) |
Apr
(31) |
May
(88) |
Jun
(48) |
Jul
(16) |
Aug
(64) |
Sep
(87) |
Oct
(92) |
Nov
(56) |
Dec
(76) |
| 2007 |
Jan
(94) |
Feb
(103) |
Mar
(126) |
Apr
(123) |
May
(85) |
Jun
(11) |
Jul
(130) |
Aug
(47) |
Sep
(65) |
Oct
(70) |
Nov
(12) |
Dec
(11) |
| 2008 |
Jan
(30) |
Feb
(55) |
Mar
(88) |
Apr
(20) |
May
(50) |
Jun
|
Jul
(38) |
Aug
(1) |
Sep
(9) |
Oct
(5) |
Nov
(6) |
Dec
(39) |
| 2009 |
Jan
(8) |
Feb
(16) |
Mar
(3) |
Apr
(33) |
May
(44) |
Jun
(1) |
Jul
(10) |
Aug
(33) |
Sep
(74) |
Oct
(22) |
Nov
|
Dec
(15) |
| 2010 |
Jan
(28) |
Feb
(22) |
Mar
(46) |
Apr
(29) |
May
(1) |
Jun
(1) |
Jul
(27) |
Aug
(8) |
Sep
(5) |
Oct
(33) |
Nov
(24) |
Dec
(41) |
| 2011 |
Jan
(4) |
Feb
(12) |
Mar
(35) |
Apr
(29) |
May
(19) |
Jun
(16) |
Jul
(32) |
Aug
(25) |
Sep
(5) |
Oct
(11) |
Nov
(21) |
Dec
(12) |
| 2012 |
Jan
(3) |
Feb
(4) |
Mar
(20) |
Apr
(4) |
May
(25) |
Jun
(13) |
Jul
|
Aug
|
Sep
(2) |
Oct
(25) |
Nov
(9) |
Dec
(1) |
| 2013 |
Jan
(6) |
Feb
(8) |
Mar
|
Apr
(10) |
May
(31) |
Jun
(7) |
Jul
(18) |
Aug
(33) |
Sep
(4) |
Oct
(16) |
Nov
|
Dec
(27) |
| 2014 |
Jan
(2) |
Feb
|
Mar
|
Apr
(11) |
May
(39) |
Jun
(8) |
Jul
(11) |
Aug
(4) |
Sep
|
Oct
(27) |
Nov
|
Dec
(71) |
| 2015 |
Jan
(17) |
Feb
(47) |
Mar
(33) |
Apr
|
May
|
Jun
(9) |
Jul
(7) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(8) |
| 2016 |
Jan
(4) |
Feb
(4) |
Mar
|
Apr
|
May
(12) |
Jun
(7) |
Jul
(9) |
Aug
(31) |
Sep
(8) |
Oct
(3) |
Nov
(15) |
Dec
(1) |
| 2017 |
Jan
(13) |
Feb
(7) |
Mar
(14) |
Apr
(8) |
May
(10) |
Jun
(4) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
(8) |
Nov
(4) |
Dec
(5) |
| 2018 |
Jan
(2) |
Feb
(8) |
Mar
|
Apr
(4) |
May
|
Jun
(6) |
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
| 2019 |
Jan
(1) |
Feb
(16) |
Mar
(1) |
Apr
(3) |
May
(5) |
Jun
(1) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
(3) |
| 2020 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
(1) |
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
(2) |
Nov
|
Dec
(2) |
| 2021 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
| 2022 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(6) |
Oct
(1) |
Nov
(1) |
Dec
(4) |
| 2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(3) |
Sep
(2) |
Oct
(2) |
Nov
(4) |
Dec
|
| 2024 |
Jan
|
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
(9) |
| 2025 |
Jan
|
Feb
(4) |
Mar
(2) |
Apr
|
May
|
Jun
|
Jul
|
Aug
(1) |
Sep
|
Oct
|
Nov
(2) |
Dec
(2) |
|
From: <sub...@co...> - 2004-12-03 14:35:27
|
Author: phd
Date: 2004-12-03 14:35:24 +0000 (Fri, 03 Dec 2004)
New Revision: 436
Modified:
home/phd/SQLObject/inheritance/sqlobject/main.py
Log:
Fixed an inconsistency: there are columns that are not in the __class__,
added with addColumn, for example, such as columns from the database.
Modified: home/phd/SQLObject/inheritance/sqlobject/main.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/main.py 2004-12-03 10:54:30 UTC (rev 435)
+++ home/phd/SQLObject/inheritance/sqlobject/main.py 2004-12-03 14:35:24 UTC (rev 436)
@@ -904,9 +904,7 @@
value = toPython(dbValue, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
- try:
- getattr(self.__class__, name)
- except AttributeError:
+ if name not in self._SO_columnDict:
raise TypeError, "%s.set() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
try:
setattr(self, name, value)
@@ -942,9 +940,7 @@
setattr(self, instanceName(name), value)
toUpdate[name] = dbValue
for name, value in extra.items():
- try:
- getattr(self.__class__, name)
- except AttributeError:
+ if name not in self._SO_columnDict:
raise TypeError, "%s.set() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
try:
setattr(self, name, value)
|
|
From: <sub...@co...> - 2004-12-03 10:54:34
|
Author: phd
Date: 2004-12-03 10:54:30 +0000 (Fri, 03 Dec 2004)
New Revision: 435
Modified:
home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py
Log:
Merged patch from rev 434: 2013 is the SERVER_LOST error.
Modified: home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py 2004-12-03 10:52:44 UTC (rev 434)
+++ home/phd/SQLObject/inheritance/sqlobject/mysql/mysqlconnection.py 2004-12-03 10:54:30 UTC (rev 435)
@@ -34,8 +34,7 @@
try:
return cursor.execute(query)
except MySQLdb.OperationalError, e:
- if e.args[0] == 2013:
- # This is a
+ if e.args[0] == 2013: # SERVER_LOST error
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
|
|
From: <sub...@co...> - 2004-12-03 10:52:48
|
Author: phd
Date: 2004-12-03 10:52:44 +0000 (Fri, 03 Dec 2004)
New Revision: 434
Modified:
trunk/SQLObject/sqlobject/mysql/mysqlconnection.py
Log:
2013 is the SERVER_LOST error.
Modified: trunk/SQLObject/sqlobject/mysql/mysqlconnection.py
===================================================================
--- trunk/SQLObject/sqlobject/mysql/mysqlconnection.py 2004-12-03 09:25:17 UTC (rev 433)
+++ trunk/SQLObject/sqlobject/mysql/mysqlconnection.py 2004-12-03 10:52:44 UTC (rev 434)
@@ -34,8 +34,7 @@
try:
return cursor.execute(query)
except MySQLdb.OperationalError, e:
- if e.args[0] == 2013:
- # This is a
+ if e.args[0] == 2013: # SERVER_LOST error
if self.debug:
self.printDebug(conn, str(e), 'ERROR')
else:
|
|
From: <sub...@co...> - 2004-12-03 09:25:19
|
Author: phd
Date: 2004-12-03 09:25:17 +0000 (Fri, 03 Dec 2004)
New Revision: 433
Modified:
home/phd/SQLObject/inheritance/sqlobject/main.py
Log:
Merged patch for rev 432: convert dbValue back toPython.
Modified: home/phd/SQLObject/inheritance/sqlobject/main.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/main.py 2004-12-03 09:24:29 UTC (rev 432)
+++ home/phd/SQLObject/inheritance/sqlobject/main.py 2004-12-03 09:25:17 UTC (rev 433)
@@ -894,9 +894,14 @@
# _SO_creating is special, see _SO_setValue
if self._SO_creating or self._lazyUpdate:
for name, value in kw.items():
- fromPy = getattr(self, '_SO_fromPython_%s' % name, None)
- if fromPy:
- kw[name] = fromPy(value, self._SO_validatorState)
+ fromPython = getattr(self, '_SO_fromPython_%s' % name, None)
+ if fromPython:
+ kw[name] = dbValue = fromPython(value, self._SO_validatorState)
+ else:
+ dbValue = value
+ toPython = getattr(self, '_SO_toPython_%s' % name, None)
+ if toPython:
+ value = toPython(dbValue, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
try:
@@ -930,9 +935,12 @@
dbValue = fromPython(value, self._SO_validatorState)
else:
dbValue = value
- toUpdate[name] = dbValue
+ toPython = getattr(self, '_SO_toPython_%s' % name, None)
+ if toPython:
+ value = toPython(dbValue, self._SO_validatorState)
if self._cacheValues:
setattr(self, instanceName(name), value)
+ toUpdate[name] = dbValue
for name, value in extra.items():
try:
getattr(self.__class__, name)
|
|
From: <sub...@co...> - 2004-12-03 09:24:36
|
Author: phd
Date: 2004-12-03 09:24:29 +0000 (Fri, 03 Dec 2004)
New Revision: 432
Modified:
trunk/SQLObject/sqlobject/main.py
Log:
Convert dbValue back toPython.
Modified: trunk/SQLObject/sqlobject/main.py
===================================================================
--- trunk/SQLObject/sqlobject/main.py 2004-12-02 19:57:06 UTC (rev 431)
+++ trunk/SQLObject/sqlobject/main.py 2004-12-03 09:24:29 UTC (rev 432)
@@ -769,9 +769,14 @@
# _SO_creating is special, see _SO_setValue
if self._SO_creating or self._lazyUpdate:
for name, value in kw.items():
- fromPy = getattr(self, '_SO_fromPython_%s' % name, None)
- if fromPy:
- kw[name] = fromPy(value, self._SO_validatorState)
+ fromPython = getattr(self, '_SO_fromPython_%s' % name, None)
+ if fromPython:
+ kw[name] = dbValue = fromPython(value, self._SO_validatorState)
+ else:
+ dbValue = value
+ toPython = getattr(self, '_SO_toPython_%s' % name, None)
+ if toPython:
+ value = toPython(dbValue, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
try:
@@ -805,9 +810,12 @@
dbValue = fromPython(value, self._SO_validatorState)
else:
dbValue = value
- toUpdate[name] = dbValue
+ toPython = getattr(self, '_SO_toPython_%s' % name, None)
+ if toPython:
+ value = toPython(dbValue, self._SO_validatorState)
if self._cacheValues:
setattr(self, instanceName(name), value)
+ toUpdate[name] = dbValue
for name, value in extra.items():
try:
getattr(self.__class__, name)
|
|
From: <sub...@co...> - 2004-12-02 19:57:11
|
Author: phd
Date: 2004-12-02 19:57:06 +0000 (Thu, 02 Dec 2004)
New Revision: 431
Modified:
home/phd/SQLObject/inheritance/docs/SQLObject.txt
home/phd/SQLObject/inheritance/examples/personaddress.py
Log:
Merged changes from trunk revisions 425:430.
Modified: home/phd/SQLObject/inheritance/docs/SQLObject.txt
===================================================================
--- home/phd/SQLObject/inheritance/docs/SQLObject.txt 2004-12-02 16:46:20 UTC (rev 430)
+++ home/phd/SQLObject/inheritance/docs/SQLObject.txt 2004-12-02 19:57:06 UTC (rev 431)
@@ -478,7 +478,8 @@
method, which is called after an object is fetched or inserted. This
method has the signature ``_init(self, id, connection=None,
selectResults=None)``, though you may just want to use ``_init(self,
-*args, **kw)``.
+*args, **kw)``. **Note:** don't forget to call
+``SQLObject._init(self, *args, **kw)`` if you override the method!
Adding Magic Attributes (properties)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Modified: home/phd/SQLObject/inheritance/examples/personaddress.py
===================================================================
--- home/phd/SQLObject/inheritance/examples/personaddress.py 2004-12-02 16:46:20 UTC (rev 430)
+++ home/phd/SQLObject/inheritance/examples/personaddress.py 2004-12-02 19:57:06 UTC (rev 431)
@@ -61,9 +61,9 @@
AND(Address.q.personID == Person.q.id,
Address.q.zip.startswith('504')))
print list(peeps)
-# SELECT person.id FROM person, phone_number
-# WHERE (phone_number.id = person.id AND
-# phone_number.phone_number LIKE '612%');
+# SELECT person.id FROM person, address
+# WHERE (address.person_id = person.id AND
+# address.zip LIKE '612%');
## end snippet
## Snippet "person-select3"
|
|
From: <sub...@co...> - 2004-12-02 16:46:25
|
Author: ianb Date: 2004-12-02 16:46:20 +0000 (Thu, 02 Dec 2004) New Revision: 430 Modified: trunk/SQLObject/docs/SQLObject.txt Log: Noted that SQLObject._init must be called, per Carlos Ribeiro's suggestion. Modified: trunk/SQLObject/docs/SQLObject.txt =================================================================== --- trunk/SQLObject/docs/SQLObject.txt 2004-12-01 16:47:40 UTC (rev 429) +++ trunk/SQLObject/docs/SQLObject.txt 2004-12-02 16:46:20 UTC (rev 430) @@ -478,7 +478,8 @@ method, which is called after an object is fetched or inserted. This method has the signature ``_init(self, id, connection=None, selectResults=None)``, though you may just want to use ``_init(self, -*args, **kw)``. +*args, **kw)``. **Note:** don't forget to call +``SQLObject._init(self, *args, **kw)`` if you override the method! Adding Magic Attributes (properties) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
From: <sub...@co...> - 2004-12-01 16:47:43
|
Author: ianb
Date: 2004-12-01 16:47:40 +0000 (Wed, 01 Dec 2004)
New Revision: 429
Modified:
trunk/SQLObject/examples/personaddress.py
Log:
Typo in a comment (propagated to the docs)
Modified: trunk/SQLObject/examples/personaddress.py
===================================================================
--- trunk/SQLObject/examples/personaddress.py 2004-12-01 14:25:00 UTC (rev 428)
+++ trunk/SQLObject/examples/personaddress.py 2004-12-01 16:47:40 UTC (rev 429)
@@ -61,9 +61,9 @@
AND(Address.q.personID == Person.q.id,
Address.q.zip.startswith('504')))
print list(peeps)
-# SELECT person.id FROM person, phone_number
-# WHERE (phone_number.id = person.id AND
-# phone_number.phone_number LIKE '612%');
+# SELECT person.id FROM person, address
+# WHERE (address.person_id = person.id AND
+# address.zip LIKE '612%');
## end snippet
## Snippet "person-select3"
|
|
From: <sub...@co...> - 2004-12-01 14:25:05
|
Author: phd Date: 2004-12-01 14:25:00 +0000 (Wed, 01 Dec 2004) New Revision: 428 Modified: home/phd/SQLObject/inheritance/docs/Inheritance.txt Log: Corrected a number of misspellings and grammar errors. Modified: home/phd/SQLObject/inheritance/docs/Inheritance.txt =================================================================== --- home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-12-01 13:06:25 UTC (rev 427) +++ home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-12-01 14:25:00 UTC (rev 428) @@ -106,20 +106,19 @@ 'inherited' classes. These clauses are the link between the id and the parent id. This will look like the following request:: - SELECT employee.id, employee.id, employee.first_name, - employee.last_name, from employee FROM person, employee WHERE - person.first_name = 'Jane' AND employee.position = 'Chief' AND person.id - = employee.id + SELECT employee.id, employee.first_name, employee.last_name + FROM person, employee WHERE person.first_name = 'Jane' + AND employee.position = 'Chief' AND person.id = employee.id Some limitation or notice about this version: -* Only simple inheritance will work. It is not possible to inherits +* Only simple inheritance will work. It is not possible to inherit from multiple SQLObject classes. -* It is possible to inherits from an inherited class and this will - works well. In the above exemple, you can have a Chief class that +* It is possible to inherit from an inherited class and this will + work well. In the above exemple, you can have a Chief class that inherits from Employee and all parents attributes will be available through the Chief class. -* You may not redefine a parent column in a inherited class (this +* You may not redefine columns in an inherited class (this will raise an exception). * If you don't want 'childName' columns in your last class (one that will never be inherited), you must set '_inheritable' to 0 in this |
|
From: <sub...@co...> - 2004-12-01 13:06:27
|
Author: phd Date: 2004-12-01 13:06:25 +0000 (Wed, 01 Dec 2004) New Revision: 427 Modified: home/phd/SQLObject/inheritance/docs/Inheritance.txt Log: Fixed a misspelling. Modified: home/phd/SQLObject/inheritance/docs/Inheritance.txt =================================================================== --- home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-12-01 13:03:37 UTC (rev 426) +++ home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-12-01 13:06:25 UTC (rev 427) @@ -40,7 +40,7 @@ A new class attribute ``_inheritable`` is added. When this new attribute is set to 1, the class is marked 'inheritable' and a new -colomns will automatically be added: childName (TEXT). +columns will automatically be added: childName (TEXT). Each class that inherits from a parent class will get the same ID as the parent class. So, there is no need to keep track of parent ID and |
|
From: <sub...@co...> - 2004-12-01 13:03:39
|
Author: phd Date: 2004-12-01 13:03:37 +0000 (Wed, 01 Dec 2004) New Revision: 426 Modified: home/phd/SQLObject/inheritance/docs/Inheritance.txt Log: Corrected plural form, changed to single (classess => class, have => has). Modified: home/phd/SQLObject/inheritance/docs/Inheritance.txt =================================================================== --- home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-12-01 12:31:13 UTC (rev 425) +++ home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-12-01 13:03:37 UTC (rev 426) @@ -3,7 +3,7 @@ Inheritance ----------- -* As suggested by Ian Bicking, each child classes now have the same +* As suggested by Ian Bicking, each child class now has the same ID than the parent class. No more need for childID column and parent foreignKey (with a small speed boost). * No more need to call getSubClass as the 'latest' child will always |
|
From: <sub...@co...> - 2004-12-01 12:31:17
|
Author: phd Date: 2004-12-01 12:31:13 +0000 (Wed, 01 Dec 2004) New Revision: 425 Modified: home/phd/SQLObject/inheritance/docs/Authors.txt home/phd/SQLObject/inheritance/docs/Inheritance.txt Log: Chnaged my address to be the real email; I am not afarid of spam, and I don't want to put a burden of editing the address on users. Fixed a minor problem (indentation) in Inheritance.txt. Modified: home/phd/SQLObject/inheritance/docs/Authors.txt =================================================================== --- home/phd/SQLObject/inheritance/docs/Authors.txt 2004-11-30 13:08:08 UTC (rev 424) +++ home/phd/SQLObject/inheritance/docs/Authors.txt 2004-12-01 12:31:13 UTC (rev 425) @@ -16,4 +16,4 @@ * Daniel Savard, Xsoli Inc <sqlobject at xsoli.com> * alexander smishlajev <alex at ank-sia.com> * Yaroslav Samchuk <yarcat at ank-sia.com> -* Oleg Broytmann <phd at phd.pp.ru> +* Oleg Broytmann <ph...@ph...> Modified: home/phd/SQLObject/inheritance/docs/Inheritance.txt =================================================================== --- home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-11-30 13:08:08 UTC (rev 424) +++ home/phd/SQLObject/inheritance/docs/Inheritance.txt 2004-12-01 12:31:13 UTC (rev 425) @@ -107,9 +107,9 @@ parent id. This will look like the following request:: SELECT employee.id, employee.id, employee.first_name, -employee.last_name, from employee FROM person, employee WHERE -person.first_name = 'Jane' AND employee.position = 'Chief' AND person.id -= employee.id + employee.last_name, from employee FROM person, employee WHERE + person.first_name = 'Jane' AND employee.position = 'Chief' AND person.id + = employee.id Some limitation or notice about this version: |
|
From: <sub...@co...> - 2004-11-30 13:08:11
|
Author: phd
Date: 2004-11-30 13:08:08 +0000 (Tue, 30 Nov 2004)
New Revision: 424
Modified:
home/phd/SQLObject/inheritance/sqlobject/main.py
Log:
Merged changes from revision 423:
Removed separartion of attributes for plain setters from ._create()
because .set() does this itself. Minor optimization in kw.items().
Do not pass child-only attributes to the parent.
Modified: home/phd/SQLObject/inheritance/sqlobject/main.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/main.py 2004-11-30 13:04:38 UTC (rev 423)
+++ home/phd/SQLObject/inheritance/sqlobject/main.py 2004-11-30 13:08:08 UTC (rev 424)
@@ -887,8 +887,9 @@
is_column = self._SO_plainSetters.has_key
f_is_column = lambda item: is_column(item[0])
f_not_column = lambda item: not is_column(item[0])
- extra = dict(filter(f_not_column, kw.items()))
- kw = dict(filter(f_is_column, kw.items()))
+ items = kw.items()
+ extra = dict(filter(f_not_column, items))
+ kw = dict(filter(f_is_column, items))
# _SO_creating is special, see _SO_setValue
if self._SO_creating or self._lazyUpdate:
@@ -898,7 +899,15 @@
kw[name] = fromPy(value, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
- setattr(self, name, value)
+ try:
+ getattr(self.__class__, name)
+ except AttributeError:
+ raise TypeError, "%s.set() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
+ try:
+ setattr(self, name, value)
+ except AttributeError, e:
+ raise AttributeError, '%s (with attribute %r)' % (e, name)
+
self._SO_createValues.update(kw)
self.dirty = True
return
@@ -925,7 +934,14 @@
if self._cacheValues:
setattr(self, instanceName(name), value)
for name, value in extra.items():
- setattr(self, name, value)
+ try:
+ getattr(self.__class__, name)
+ except AttributeError:
+ raise TypeError, "%s.set() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
+ try:
+ setattr(self, name, value)
+ except AttributeError, e:
+ raise AttributeError, '%s (with attribute %r)' % (e, name)
if toUpdate:
args = [(self._SO_columnDict[name].dbName, value)
@@ -1002,8 +1018,13 @@
#DSM: If we are the children of an inheritable class,
#DSM: we must first create our parent
if self._parentClass:
- #kw['childName'] = inst._className
- self._parent = self._parentClass(kw=kw)
+ parentClass = self._parentClass
+ parent_kw = dict(
+ [(name, value) for (name, value) in kw.items()
+ if hasattr(parentClass, name)
+ ]
+ )
+ self._parent = parentClass(kw=parent_kw)
self._parent.childName = self._className
id = self._parent.id
@@ -1033,35 +1054,8 @@
# that keyword:
kw[column.name] = default
- # We sort out what columns go straight into the database,
- # and which ones need setattr() directly here:
- forDB = {}
- others = {}
- for name, value in kw.items():
- if name in self._SO_plainSetters:
- forDB[name] = value
- #DSM: If this is a call from the child,
- #DSM: we must remove the parameter for the database
- if fromChild: del kw[name]
- elif not fromChild:
- #DSM: Only use other items if this isn't a call from the child
- others[name] = value
+ self.set(**kw)
- # We take all the straight-to-DB values and use set() to
- # set them:
- self.set(**forDB)
-
- # The rest go through setattr():
- for name, value in others.items():
- try:
- getattr(self.__class__, name)
- except AttributeError:
- raise TypeError, "%s() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
- try:
- setattr(self, name, value)
- except AttributeError, e:
- raise AttributeError, '%s (with attribute %r)' % (e, name)
-
# Then we finalize the process:
self._SO_finishCreate(id)
|
|
From: <sub...@co...> - 2004-11-30 13:04:40
|
Author: phd
Date: 2004-11-30 13:04:38 +0000 (Tue, 30 Nov 2004)
New Revision: 423
Modified:
trunk/SQLObject/sqlobject/main.py
Log:
Removed separartion of attributes for plain setters from ._create()
because .set() does this itself. Minor optimization in kw.items().
Modified: trunk/SQLObject/sqlobject/main.py
===================================================================
--- trunk/SQLObject/sqlobject/main.py 2004-11-30 12:57:41 UTC (rev 422)
+++ trunk/SQLObject/sqlobject/main.py 2004-11-30 13:04:38 UTC (rev 423)
@@ -762,8 +762,9 @@
is_column = self._SO_plainSetters.has_key
f_is_column = lambda item: is_column(item[0])
f_not_column = lambda item: not is_column(item[0])
- extra = dict(filter(f_not_column, kw.items()))
- kw = dict(filter(f_is_column, kw.items()))
+ items = kw.items()
+ extra = dict(filter(f_not_column, items))
+ kw = dict(filter(f_is_column, items))
# _SO_creating is special, see _SO_setValue
if self._SO_creating or self._lazyUpdate:
@@ -773,7 +774,15 @@
kw[name] = fromPy(value, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
- setattr(self, name, value)
+ try:
+ getattr(self.__class__, name)
+ except AttributeError:
+ raise TypeError, "%s.set() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
+ try:
+ setattr(self, name, value)
+ except AttributeError, e:
+ raise AttributeError, '%s (with attribute %r)' % (e, name)
+
self._SO_createValues.update(kw)
self.dirty = True
return
@@ -800,7 +809,14 @@
if self._cacheValues:
setattr(self, instanceName(name), value)
for name, value in extra.items():
- setattr(self, name, value)
+ try:
+ getattr(self.__class__, name)
+ except AttributeError:
+ raise TypeError, "%s.set() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
+ try:
+ setattr(self, name, value)
+ except AttributeError, e:
+ raise AttributeError, '%s (with attribute %r)' % (e, name)
if toUpdate:
args = [(self._SO_columnDict[name].dbName, value)
@@ -891,31 +907,8 @@
# that keyword:
kw[column.name] = default
- # We sort out what columns go straight into the database,
- # and which ones need setattr() directly here:
- forDB = {}
- others = {}
- for name, value in kw.items():
- if name in self._SO_plainSetters:
- forDB[name] = value
- else:
- others[name] = value
+ self.set(**kw)
- # We take all the straight-to-DB values and use set() to
- # set them:
- self.set(**forDB)
-
- # The rest go through setattr():
- for name, value in others.items():
- try:
- getattr(self.__class__, name)
- except AttributeError:
- raise TypeError, "%s() got an unexpected keyword argument %s" % (self.__class__.__name__, name)
- try:
- setattr(self, name, value)
- except AttributeError, e:
- raise AttributeError, '%s (with attribute %r)' % (e, name)
-
# Then we finalize the process:
self._SO_finishCreate(id)
|
|
From: <sub...@co...> - 2004-11-30 12:57:43
|
Author: phd
Date: 2004-11-30 12:57:41 +0000 (Tue, 30 Nov 2004)
New Revision: 422
Modified:
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Merged fix from revision 421: replaced usage() with sys.exit() and an error message.
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2004-11-30 12:56:55 UTC (rev 421)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2004-11-30 12:57:41 UTC (rev 422)
@@ -1340,7 +1340,7 @@
["database=", "extra-verbose", "super-verbose",
"inserts", "coverage"])
except GetoptError:
- usage(1)
+ sys.exit("Usage: %s [-d|--database all|type] [-v[v]] [--extra-verbose|--super-verbose] [--inserts] [--coverage]" % sys.argv[0])
dbs = []
newArgs = []
|
|
From: <sub...@co...> - 2004-11-30 12:57:01
|
Author: phd
Date: 2004-11-30 12:56:55 +0000 (Tue, 30 Nov 2004)
New Revision: 421
Modified:
trunk/SQLObject/tests/test_sqlobject.py
Log:
Fixed a bug: replaced usage() with sys.exit() and an error message.
Modified: trunk/SQLObject/tests/test_sqlobject.py
===================================================================
--- trunk/SQLObject/tests/test_sqlobject.py 2004-11-29 21:30:03 UTC (rev 420)
+++ trunk/SQLObject/tests/test_sqlobject.py 2004-11-30 12:56:55 UTC (rev 421)
@@ -1340,7 +1340,7 @@
["database=", "extra-verbose", "super-verbose",
"inserts", "coverage"])
except GetoptError:
- usage(1)
+ sys.exit("Usage: %s [-d|--database all|type] [-v[v]] [--extra-verbose|--super-verbose] [--inserts] [--coverage]" % sys.argv[0])
dbs = []
newArgs = []
|
|
From: <sub...@co...> - 2004-11-29 21:30:09
|
Author: phd
Date: 2004-11-29 21:30:03 +0000 (Mon, 29 Nov 2004)
New Revision: 420
Modified:
home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py
Log:
Merged changes 418:419: test the server's version and adapt DROP TABLE (do not use CASCADE in version 7.2 or earlier).
Modified: home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py 2004-11-29 21:27:38 UTC (rev 419)
+++ home/phd/SQLObject/inheritance/sqlobject/postgres/pgconnection.py 2004-11-29 21:30:03 UTC (rev 420)
@@ -39,6 +39,9 @@
self.dsn = dsn
DBAPI.__init__(self, **kw)
+ # Server version cache
+ self._server_version = None # Not yet initialized
+
def connectionFromURI(cls, uri):
user, password, host, path, args = cls._parseURI(uri)
path = path.strip('/')
@@ -93,6 +96,8 @@
return '%s SERIAL PRIMARY KEY' % soClass._idName
def dropTable(self, tableName, cascade=False):
+ if self.server_version[:3] <= "7.2":
+ cascade=False
self.query("DROP TABLE %s %s" % (tableName,
cascade and 'CASCADE' or ''))
@@ -198,3 +203,11 @@
else:
return col.Col, {}
+ def server_version(self):
+ if self._server_version is None:
+ # The result is something like
+ # ' PostgreSQL 7.2.1 on i686-pc-linux-gnu, compiled by GCC 2.95.4'
+ server_version = self.queryOne("SELECT version()")[0]
+ self._server_version = server_version.split()[1]
+ return self._server_version
+ server_version = property(server_version)
|
|
From: <sub...@co...> - 2004-11-29 21:27:40
|
Author: phd
Date: 2004-11-29 21:27:38 +0000 (Mon, 29 Nov 2004)
New Revision: 419
Modified:
trunk/SQLObject/sqlobject/postgres/pgconnection.py
Log:
Test the server's version and adapt DROP TABLE (do not use CASCADE in version 7.2 or earlier).
Modified: trunk/SQLObject/sqlobject/postgres/pgconnection.py
===================================================================
--- trunk/SQLObject/sqlobject/postgres/pgconnection.py 2004-11-29 19:19:41 UTC (rev 418)
+++ trunk/SQLObject/sqlobject/postgres/pgconnection.py 2004-11-29 21:27:38 UTC (rev 419)
@@ -39,6 +39,9 @@
self.dsn = dsn
DBAPI.__init__(self, **kw)
+ # Server version cache
+ self._server_version = None # Not yet initialized
+
def connectionFromURI(cls, uri):
user, password, host, path, args = cls._parseURI(uri)
path = path.strip('/')
@@ -93,6 +96,8 @@
return '%s SERIAL PRIMARY KEY' % soClass._idName
def dropTable(self, tableName, cascade=False):
+ if self.server_version[:3] <= "7.2":
+ cascade=False
self.query("DROP TABLE %s %s" % (tableName,
cascade and 'CASCADE' or ''))
@@ -198,3 +203,11 @@
else:
return col.Col, {}
+ def server_version(self):
+ if self._server_version is None:
+ # The result is something like
+ # ' PostgreSQL 7.2.1 on i686-pc-linux-gnu, compiled by GCC 2.95.4'
+ server_version = self.queryOne("SELECT version()")[0]
+ self._server_version = server_version.split()[1]
+ return self._server_version
+ server_version = property(server_version)
|
|
From: <sub...@co...> - 2004-11-29 19:19:43
|
Author: phd
Date: 2004-11-29 19:19:41 +0000 (Mon, 29 Nov 2004)
New Revision: 418
Modified:
home/phd/SQLObject/inheritance/sqlobject/main.py
home/phd/SQLObject/inheritance/tests/test_sqlobject.py
Log:
Merged fixes from the trunk.
Modified: home/phd/SQLObject/inheritance/sqlobject/main.py
===================================================================
--- home/phd/SQLObject/inheritance/sqlobject/main.py 2004-11-29 19:13:59 UTC (rev 417)
+++ home/phd/SQLObject/inheritance/sqlobject/main.py 2004-11-29 19:19:41 UTC (rev 418)
@@ -895,7 +895,7 @@
for name, value in kw.items():
fromPy = getattr(self, '_SO_fromPython_%s' % name, None)
if fromPy:
- kw[name] = value = fromPy(value, self._SO_validatorState)
+ kw[name] = fromPy(value, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
setattr(self, name, value)
Modified: home/phd/SQLObject/inheritance/tests/test_sqlobject.py
===================================================================
--- home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2004-11-29 19:13:59 UTC (rev 417)
+++ home/phd/SQLObject/inheritance/tests/test_sqlobject.py 2004-11-29 19:19:41 UTC (rev 418)
@@ -34,7 +34,7 @@
class Duplicate(SQLObject):
pass
except ValueError, err:
- self.assertEqual(str(err), "class Duplicate is already in the registry")
+ assert str(err).startswith("class Duplicate is already in the registry")
else:
self.fail("should have raised an error on duplicate class definition")
@@ -1198,14 +1198,9 @@
n += 1
SOIndex1(name=name, number=n)
mod = SOIndex1._connection.module
- # Firebird doesn't throw an integrity error, unfortunately:
- if mod.__name__.endswith('kinterbasdb'):
- exc = mod.ProgrammingError
- else:
- exc = mod.IntegrityError
try:
SOIndex1(name='blah', number=0)
- except exc:
+ except (mod.ProgrammingError, mod.IntegrityError):
# expected
pass
else:
|
|
From: <sub...@co...> - 2004-11-29 19:14:02
|
Author: phd
Date: 2004-11-29 19:13:59 +0000 (Mon, 29 Nov 2004)
New Revision: 417
Modified:
trunk/SQLObject/sqlobject/main.py
Log:
dbValue is never used in the snippet.
Modified: trunk/SQLObject/sqlobject/main.py
===================================================================
--- trunk/SQLObject/sqlobject/main.py 2004-11-29 19:11:36 UTC (rev 416)
+++ trunk/SQLObject/sqlobject/main.py 2004-11-29 19:13:59 UTC (rev 417)
@@ -770,7 +770,7 @@
for name, value in kw.items():
fromPy = getattr(self, '_SO_fromPython_%s' % name, None)
if fromPy:
- kw[name] = dbValue = fromPy(value, self._SO_validatorState)
+ kw[name] = fromPy(value, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
setattr(self, name, value)
|
|
From: <sub...@co...> - 2004-11-29 19:11:41
|
Author: phd
Date: 2004-11-29 19:11:36 +0000 (Mon, 29 Nov 2004)
New Revision: 416
Added:
trunk/SQLObject/tests/test_sqlobject.py
Removed:
trunk/SQLObject/tests/test.py
Modified:
trunk/SQLObject/test
Log:
Renamed tests/test.py to tests/test_sqlobject.py to allow import from it (and not from python test).
Modified: trunk/SQLObject/test
===================================================================
--- trunk/SQLObject/test 2004-11-29 19:10:10 UTC (rev 415)
+++ trunk/SQLObject/test 2004-11-29 19:11:36 UTC (rev 416)
@@ -11,8 +11,8 @@
if [ "$1" = "cover" ] ; then
shift
sudo python$VERSION setup.py -q install
- python$VERSION ./tests/coverage.py -x tests/test.py $*
+ python$VERSION ./tests/coverage.py -x tests/test_sqlobject.py $*
./tests/coverage.py -a `find tests SQLObject -name '*.py'`
else
- sudo python$VERSION setup.py -q install && python$VERSION tests/test.py $*
+ sudo python$VERSION setup.py -q install && python$VERSION tests/test_sqlobject.py $*
fi
Deleted: trunk/SQLObject/tests/test.py
===================================================================
--- trunk/SQLObject/tests/test.py 2004-11-29 19:10:10 UTC (rev 415)
+++ trunk/SQLObject/tests/test.py 2004-11-29 19:11:36 UTC (rev 416)
@@ -1,1390 +0,0 @@
-"""
-Main unit testing for SQLObject.
-
-Use -vv to see SQL queries, -vvv to also see output from queries,
-and together with --inserts to see the SQL from the standard
-insert statements (which are often boring).
-"""
-
-from __future__ import generators
-
-import sys, os
-if '--coverage' in sys.argv:
- import coverage
- print 'Starting coverage'
- coverage.erase()
- coverage.start()
-
-from SQLObjectTest import *
-from sqlobject import *
-from sqlobject.include import validators
-from sqlobject import classregistry
-from mx import DateTime
-global curr_db
-curr_db = None
-from sqlobject import cache
-
-class ClassRegistryTest(SQLObjectTest):
- def testErrorOnDuplicateClassDefinition(self):
- """Raise an error if a class is defined more than once."""
- class Duplicate(SQLObject):
- pass
-
- try:
- class Duplicate(SQLObject):
- pass
- except ValueError, err:
- assert str(err).startswith("class Duplicate is already in the registry")
- else:
- self.fail("should have raised an error on duplicate class definition")
-
-########################################
-## Basic operation
-########################################
-
-class TestSO1(SQLObject):
-
- name = StringCol(length=50, dbName='name_col')
- _cacheValues = False
- _columns = [
- StringCol('passwd', length=10),
- ]
-
- def _set_passwd(self, passwd):
- self._SO_set_passwd(passwd.encode('rot13'))
-
-class TestCase1(SQLObjectTest):
-
- classes = [TestSO1]
- MyClass = TestSO1
-
- info = [('bob', 'god'), ('sally', 'sordid'),
- ('dave', 'dremel'), ('fred', 'forgo')]
-
- def inserts(self):
- for name, passwd in self.info:
- self.MyClass(name=name, passwd=passwd)
-
- def testGet(self):
- bob = self.MyClass.selectBy(name='bob')[0]
- self.assertEqual(bob.name, 'bob')
- self.assertEqual(bob.passwd, 'god'.encode('rot13'))
-
- def testNewline(self):
- bob = self.MyClass.selectBy(name='bob')[0]
- testString = 'hey\nyou\\can\'t you see me?\t'
- bob.name = testString
- self.failUnless(bob.name == testString, (bob.name, testString))
-
- def testCount(self):
- self.assertEqual(self.MyClass.selectBy(name='bob').count(), 1)
- self.assertEqual(self.MyClass.select(self.MyClass.q.name == 'bob').count(), 1)
- self.assertEqual(self.MyClass.select().count(), len(list(self.MyClass.select())))
-
-class TestCaseGetSet(TestCase1):
-
- def testGet(self):
- bob = TestSO1.selectBy(name='bob')[0]
- self.assertEqual(bob.name, 'bob')
- bob.name = 'joe'
- self.assertEqual(bob.name, 'joe')
-
-
-class TestSO2(SQLObject):
- name = StringCol(length=50, dbName='name_col')
- passwd = StringCol(length=10)
-
- def _set_passwd(self, passwd):
- self._SO_set_passwd(passwd.encode('rot13'))
-
-class TestCase2(TestCase1):
-
- classes = [TestSO2]
- MyClass = TestSO2
-
-class TestSO3(SQLObject):
- name = StringCol(length=10, dbName='name_col')
- other = ForeignKey('TestSO4', default=None)
- other2 = KeyCol(foreignKey='TestSO4', default=None)
-
-class TestSO4(SQLObject):
- me = StringCol(length=10)
-
-class Student(SQLObject):
- is_smart = BoolCol()
-
-class BoolColTest(SQLObjectTest):
- classes = [Student]
-
- def testBoolCol(self):
- student = Student(is_smart=False)
- self.assertEqual(student.is_smart, False)
- student2 = Student(is_smart='false')
- self.assertEqual(student2.is_smart, True)
-
-class TestCase34(SQLObjectTest):
-
- classes = [TestSO4, TestSO3]
-
- def testForeignKey(self):
- tc3 = TestSO3(name='a')
- self.assertEqual(tc3.other, None)
- self.assertEqual(tc3.other2, None)
- self.assertEqual(tc3.otherID, None)
- self.assertEqual(tc3.other2ID, None)
- tc4a = TestSO4(me='1')
- tc3.other = tc4a
- self.assertEqual(tc3.other, tc4a)
- self.assertEqual(tc3.otherID, tc4a.id)
- tc4b = TestSO4(me='2')
- tc3.other = tc4b.id
- self.assertEqual(tc3.other, tc4b)
- self.assertEqual(tc3.otherID, tc4b.id)
- tc4c = TestSO4(me='3')
- tc3.other2 = tc4c
- self.assertEqual(tc3.other2, tc4c)
- self.assertEqual(tc3.other2ID, tc4c.id)
- tc4d = TestSO4(me='4')
- tc3.other2 = tc4d.id
- self.assertEqual(tc3.other2, tc4d)
- self.assertEqual(tc3.other2ID, tc4d.id)
- tcc = TestSO3(name='b', other=tc4a)
- self.assertEqual(tcc.other, tc4a)
- tcc2 = TestSO3(name='c', other=tc4a.id)
- self.assertEqual(tcc2.other, tc4a)
-
-class TestSO5(SQLObject):
- name = StringCol(length=10, dbName='name_col')
- other = ForeignKey('TestSO6', default=None, cascade=True)
- another = ForeignKey('TestSO7', default=None, cascade=True)
-
-class TestSO6(SQLObject):
- name = StringCol(length=10, dbName='name_col')
- other = ForeignKey('TestSO7', default=None, cascade=True)
-
-class TestSO7(SQLObject):
- name = StringCol(length=10, dbName='name_col')
-
-class TestCase567(SQLObjectTest):
-
- classes = [TestSO7, TestSO6, TestSO5]
-
- def testForeignKeyDestroySelfCascade(self):
- tc5 = TestSO5(name='a')
- tc6a = TestSO6(name='1')
- tc5.other = tc6a
- tc7a = TestSO7(name='2')
- tc6a.other = tc7a
- tc5.another = tc7a
- self.assertEqual(tc5.other, tc6a)
- self.assertEqual(tc5.otherID, tc6a.id)
- self.assertEqual(tc6a.other, tc7a)
- self.assertEqual(tc6a.otherID, tc7a.id)
- self.assertEqual(tc5.other.other, tc7a)
- self.assertEqual(tc5.other.otherID, tc7a.id)
- self.assertEqual(tc5.another, tc7a)
- self.assertEqual(tc5.anotherID, tc7a.id)
- self.assertEqual(tc5.other.other, tc5.another)
- self.assertEqual(TestSO5.select().count(), 1)
- self.assertEqual(TestSO6.select().count(), 1)
- self.assertEqual(TestSO7.select().count(), 1)
- tc6b = TestSO6(name='3')
- tc6c = TestSO6(name='4')
- tc7b = TestSO7(name='5')
- tc6b.other = tc7b
- tc6c.other = tc7b
- self.assertEqual(TestSO5.select().count(), 1)
- self.assertEqual(TestSO6.select().count(), 3)
- self.assertEqual(TestSO7.select().count(), 2)
- tc6b.destroySelf()
- self.assertEqual(TestSO5.select().count(), 1)
- self.assertEqual(TestSO6.select().count(), 2)
- self.assertEqual(TestSO7.select().count(), 2)
- tc7b.destroySelf()
- self.assertEqual(TestSO5.select().count(), 1)
- self.assertEqual(TestSO6.select().count(), 1)
- self.assertEqual(TestSO7.select().count(), 1)
- tc7a.destroySelf()
- self.assertEqual(TestSO5.select().count(), 0)
- self.assertEqual(TestSO6.select().count(), 0)
- self.assertEqual(TestSO7.select().count(), 0)
-
- def testForeignKeyDropTableCascade(self):
- if curr_db == 'sybase':
- # XXX This test doesn't pass with sybase.
- return
- tc5a = TestSO5(name='a')
- tc6a = TestSO6(name='1')
- tc5a.other = tc6a
- tc7a = TestSO7(name='2')
- tc6a.other = tc7a
- tc5a.another = tc7a
- tc5b = TestSO5(name='b')
- tc5c = TestSO5(name='c')
- tc6b = TestSO6(name='3')
- tc5c.other = tc6b
- self.assertEqual(TestSO5.select().count(), 3)
- self.assertEqual(TestSO6.select().count(), 2)
- self.assertEqual(TestSO7.select().count(), 1)
- TestSO7.dropTable(cascade=True)
- self.assertEqual(TestSO5.select().count(), 3)
- self.assertEqual(TestSO6.select().count(), 2)
- tc6a.destroySelf()
- self.assertEqual(TestSO5.select().count(), 2)
- self.assertEqual(TestSO6.select().count(), 1)
- tc6b.destroySelf()
- self.assertEqual(TestSO5.select().count(), 1)
- self.assertEqual(TestSO6.select().count(), 0)
- self.assertEqual(iter(TestSO5.select()).next(), tc5b)
- tc6c = TestSO6(name='3')
- tc5b.other = tc6c
- self.assertEqual(TestSO5.select().count(), 1)
- self.assertEqual(TestSO6.select().count(), 1)
- tc6c.destroySelf()
- self.assertEqual(TestSO5.select().count(), 0)
- self.assertEqual(TestSO6.select().count(), 0)
-
-class TestSO8(SQLObject):
- name = StringCol(length=10, dbName='name_col')
- other = ForeignKey('TestSO9', default=None, cascade=False)
-
-class TestSO9(SQLObject):
- name = StringCol(length=10, dbName='name_col')
-
-class TestCase89(SQLObjectTest):
-
- classes = [TestSO9, TestSO8]
-
- def testForeignKeyDestroySelfRestrict(self):
- tc8a = TestSO8(name='a')
- tc9a = TestSO9(name='1')
- tc8a.other = tc9a
- tc8b = TestSO8(name='b')
- tc9b = TestSO9(name='2')
- self.assertEqual(tc8a.other, tc9a)
- self.assertEqual(tc8a.otherID, tc9a.id)
- self.assertEqual(TestSO8.select().count(), 2)
- self.assertEqual(TestSO9.select().count(), 2)
- self.assertRaises(Exception, tc9a.destroySelf)
- tc9b.destroySelf()
- self.assertEqual(TestSO8.select().count(), 2)
- self.assertEqual(TestSO9.select().count(), 1)
- tc8a.destroySelf()
- tc8b.destroySelf()
- tc9a.destroySelf()
- self.assertEqual(TestSO8.select().count(), 0)
- self.assertEqual(TestSO9.select().count(), 0)
-
-########################################
-## Fancy sort
-########################################
-
-class Names(SQLObject):
-
- _table = 'names_table'
-
- firstName = StringCol(length=30)
- lastName = StringCol(length=30)
-
- _defaultOrder = ['lastName', 'firstName']
-
-class NamesTest(SQLObjectTest):
-
- classes = [Names]
-
- def inserts(self):
- for firstName, lastName in [('aj', 'baker'), ('joe', 'robbins'),
- ('tim', 'jackson'), ('joe', 'baker'),
- ('zoe', 'robbins')]:
- Names(firstName=firstName, lastName=lastName)
-
- def testDefaultOrder(self):
- self.assertEqual([(n.firstName, n.lastName) for n in Names.select()],
- [('aj', 'baker'), ('joe', 'baker'),
- ('tim', 'jackson'), ('joe', 'robbins'),
- ('zoe', 'robbins')])
-
- def testOtherOrder(self):
- self.assertEqual([(n.firstName, n.lastName) for n in Names.select().orderBy(['firstName', 'lastName'])],
- [('aj', 'baker'), ('joe', 'baker'),
- ('joe', 'robbins'), ('tim', 'jackson'),
- ('zoe', 'robbins')])
-
- def testUntranslatedColumnOrder(self):
- self.assertEqual([(n.firstName, n.lastName) for n in Names.select().orderBy(['first_name', 'last_name'])],
- [('aj', 'baker'), ('joe', 'baker'),
- ('joe', 'robbins'), ('tim', 'jackson'),
- ('zoe', 'robbins')])
-
- def testSingleUntranslatedColumnOrder(self):
- self.assertEqual([n.firstName for n in
- Names.select().orderBy('firstName')],
- ['aj', 'joe', 'joe', 'tim', 'zoe'])
- self.assertEqual([n.firstName for n in
- Names.select().orderBy('first_name')],
- ['aj', 'joe', 'joe', 'tim', 'zoe'])
- self.assertEqual([n.firstName for n in
- Names.select().orderBy('-firstName')],
- ['zoe', 'tim', 'joe', 'joe', 'aj'])
- self.assertEqual([n.firstName for n in
- Names.select().orderBy('-first_name')],
- ['zoe', 'tim', 'joe', 'joe', 'aj'])
- self.assertEqual([n.firstName for n in
- Names.select().orderBy(Names.q.firstName)],
- ['aj', 'joe', 'joe', 'tim', 'zoe'])
-
-########################################
-## Select results
-########################################
-
-class IterTest(SQLObject):
- name = StringCol(dbName='name_col')
-
-class IterationTestCase(SQLObjectTest):
- '''Test basic iteration techniques'''
-
- classes = [IterTest]
-
- names = ('a', 'b', 'c')
-
- def inserts(self):
- for name in self.names:
- IterTest(name=name)
-
- def test_00_normal(self):
- count = 0
- for test in IterTest.select():
- count += 1
- self.failIf(count != len(self.names))
-
- def test_01_turn_to_list(self):
- count = 0
- for test in list(IterTest.select()):
- count += 1
- self.failIf(count != len(self.names))
-
- def test_02_generator(self):
- def enumerate(iterable):
- i = 0
- for obj in iterable:
- yield i, obj
- i += 1
- all = IterTest.select()
- count = 0
- for i, test in enumerate(all):
- count += 1
- self.failIf(count != len(self.names))
-
- def test_03_ranged_indexed(self):
- all = IterTest.select()
- count = 0
- for i in range(all.count()):
- test = all[i]
- count += 1
- self.failIf(count != len(self.names))
-
- def test_04_indexed_ended_by_exception(self):
- all = IterTest.select()
- count = 0
- try:
- while 1:
- test = all[count]
- count = count+1
- # Stop the test if it's gone on too long
- if count > len(self.names):
- break
- except IndexError:
- pass
- self.assertEqual(count, len(self.names))
-
-
-########################################
-## Delete during select
-########################################
-
-
-class DeleteSelectTest(TestCase1):
-
- def testGet(self):
- return
-
- def testSelect(self):
- for obj in TestSO1.select('all'):
- obj.destroySelf()
- self.assertEqual(list(TestSO1.select('all')), [])
-
-########################################
-## Delete without caching
-########################################
-
-class NoCache(SQLObject):
- name = StringCol()
-
-class TestNoCache(SQLObjectTest):
-
- classes=[NoCache]
-
- def setUp(self):
- SQLObjectTest.setUp(self)
- NoCache._connection.cache = cache.CacheSet(cache=False)
-
- def tearDown(self):
- NoCache._connection.cache = cache.CacheSet(cache=True)
- SQLObjectTest.tearDown(self)
-
- def testDestroySelf(self):
- value = NoCache(name='test')
- value.destroySelf()
-
-########################################
-## Transaction test
-########################################
-
-class TestSOTrans(SQLObject):
- #_cacheValues = False
- name = StringCol(length=10, alternateID=True, dbName='name_col')
- _defaultOrderBy = 'name'
-
-class TransactionTest(SQLObjectTest):
-
- classes = [TestSOTrans]
-
- def inserts(self):
- TestSOTrans(name='bob')
- TestSOTrans(name='tim')
-
- def testTransaction(self):
- if not self.supportTransactions: return
- trans = TestSOTrans._connection.transaction()
- try:
- TestSOTrans._connection.autoCommit = 'exception'
- TestSOTrans(name='joe', connection=trans)
- trans.rollback()
- trans.begin()
- self.assertEqual([n.name for n in TestSOTrans.select(connection=trans)],
- ['bob', 'tim'])
- b = TestSOTrans.byName('bob', connection=trans)
- b.name = 'robert'
- trans.commit()
- self.assertEqual(b.name, 'robert')
- b.name = 'bob'
- trans.rollback()
- trans.begin()
- self.assertEqual(b.name, 'robert')
- finally:
- TestSOTrans._connection.autoCommit = True
-
-
-########################################
-## Enum test
-########################################
-
-class Enum1(SQLObject):
-
- _columns = [
- EnumCol('l', enumValues=['a', 'bcd', 'e']),
- ]
-
-class TestEnum1(SQLObjectTest):
-
- classes = [Enum1]
-
- def inserts(self):
- for l in ['a', 'bcd', 'a', 'e']:
- Enum1(l=l)
-
- def testBad(self):
- if self.supportRestrictedEnum:
- try:
- v = Enum1(l='b')
- except Exception, e:
- pass
- else:
- print v
- assert 0, "This should cause an error"
-
-
-########################################
-## Slicing tests
-########################################
-
-class Counter(SQLObject):
-
- _columns = [
- IntCol('number', notNull=True),
- ]
-
-class SliceTest(SQLObjectTest):
-
- classes = [Counter]
-
- def inserts(self):
- for i in range(100):
- Counter(number=i)
-
- def counterEqual(self, counters, value):
- self.assertEquals([c.number for c in counters], value)
-
- def test1(self):
- self.counterEqual(Counter.select('all', orderBy='number'), range(100))
-
- def test2(self):
- self.counterEqual(Counter.select('all', orderBy='number')[10:20],
- range(10, 20))
-
- def test3(self):
- self.counterEqual(Counter.select('all', orderBy='number')[20:30][:5],
- range(20, 25))
-
- def test4(self):
- self.counterEqual(Counter.select('all', orderBy='number')[:-10],
- range(0, 90))
-
- def test5(self):
- self.counterEqual(Counter.select('all', orderBy='number', reversed=True), range(99, -1, -1))
-
- def test6(self):
- self.counterEqual(Counter.select('all', orderBy='-number'), range(99, -1, -1))
-
-
-########################################
-## Select tests
-########################################
-
-class Counter2(SQLObject):
-
- _columns = [
- IntCol('n1', notNull=True),
- IntCol('n2', notNull=True),
- ]
-
-class SelectTest(SQLObjectTest):
-
- classes = [Counter2]
-
- def inserts(self):
- for i in range(10):
- for j in range(10):
- Counter2(n1=i, n2=j)
-
- def counterEqual(self, counters, value):
- self.assertEquals([(c.n1, c.n2) for c in counters], value)
-
- def accumulateEqual(self, func, counters, value):
- self.assertEqual(func([ c.n1 for c in counters]), value)
-
- def test1(self):
- self.accumulateEqual(sum,Counter2.select(orderBy='n1'),
- sum(range(10)) * 10)
-
- def test2(self):
- self.accumulateEqual(len,Counter2.select('all'), 100)
-
-
-########################################
-## Dynamic column tests
-########################################
-
-class Person(SQLObject):
-
- _columns = [StringCol('name', length=100, dbName='name_col')]
- _defaultOrder = 'name'
-
-class Phone(SQLObject):
-
- _columns = [StringCol('phone', length=12)]
- _defaultOrder = 'phone'
-
-class PeopleTest(SQLObjectTest):
-
- classes = [Person, Phone]
-
- def inserts(self):
- for n in ['jane', 'tim', 'bob', 'jake']:
- Person(name=n)
- for p in ['555-555-5555', '555-394-2930',
- '444-382-4854']:
- Phone(phone=p)
-
- def testDefaultOrder(self):
- self.assertEqual(list(Person.select('all')),
- list(Person.select('all', orderBy=Person._defaultOrder)))
-
- def testDynamicColumn(self):
- if not self.supportDynamic:
- return
- nickname = StringCol('nickname', length=10)
- Person.addColumn(nickname, changeSchema=True)
- n = Person(name='robert', nickname='bob')
- self.assertEqual([p.name for p in Person.select('all')],
- ['bob', 'jake', 'jane', 'robert', 'tim'])
- Person.delColumn(nickname, changeSchema=True)
-
- def testDynamicJoin(self):
- if not self.supportDynamic:
- return
- col = KeyCol('personID', foreignKey='Person')
- Phone.addColumn(col, changeSchema=True)
- join = MultipleJoin('Phone')
- Person.addJoin(join)
- for phone in Phone.select('all'):
- if phone.phone.startswith('555'):
- phone.person = Person.selectBy(name='tim')[0]
- else:
- phone.person = Person.selectBy(name='bob')[0]
- l = [p.phone for p in Person.selectBy(name='tim')[0].phones]
- l.sort()
- self.assertEqual(l,
- ['555-394-2930', '555-555-5555'])
- Phone.delColumn(col, changeSchema=True)
- Person.delJoin(join)
-
-########################################
-## Auto class generation
-########################################
-
-class AutoTest(SQLObjectTest):
-
- mysqlCreate = """
- CREATE TABLE IF NOT EXISTS auto_test (
- auto_id INT AUTO_INCREMENT PRIMARY KEY,
- first_name VARCHAR(100),
- last_name VARCHAR(200) NOT NULL,
- age INT DEFAULT NULL,
- created DATETIME NOT NULL,
- happy char(1) DEFAULT 'Y' NOT NULL,
- wannahavefun TINYINT DEFAULT 0 NOT NULL
- )
- """
-
- postgresCreate = """
- CREATE TABLE auto_test (
- auto_id SERIAL PRIMARY KEY,
- first_name VARCHAR(100),
- last_name VARCHAR(200) NOT NULL,
- age INT DEFAULT 0,
- created VARCHAR(40) NOT NULL,
- happy char(1) DEFAULT 'Y' NOT NULL,
- wannahavefun BOOL DEFAULT FALSE NOT NULL
- )
- """
-
- sybaseCreate = """
- CREATE TABLE auto_test (
- auto_id integer,
- first_name VARCHAR(100),
- last_name VARCHAR(200) NOT NULL,
- age INT DEFAULT 0,
- created VARCHAR(40) NOT NULL,
- happy char(1) DEFAULT 'Y' NOT NULL
- )
- """
-
- mysqlDrop = """
- DROP TABLE IF EXISTS auto_test
- """
-
- postgresDrop = """
- DROP TABLE auto_test
- """
-
- sybaseDrop = """
- DROP TABLE auto_test
- """
-
- _table = 'auto_test'
-
- def testClassCreate(self):
- if not self.supportAuto:
- return
- class AutoTest(SQLObject):
- _fromDatabase = True
- _idName = 'auto_id'
- _connection = connection()
- john = AutoTest(firstName='john',
- lastName='doe',
- age=10,
- created=DateTime.now(),
- wannahavefun=False)
- jane = AutoTest(firstName='jane',
- lastName='doe',
- happy='N',
- created=DateTime.now(),
- wannahavefun=True)
- self.failIf(john.wannahavefun)
- self.failUnless(jane.wannahavefun)
- del classregistry.registry(AutoTest._registry).classes['AutoTest']
-
-########################################
-## Joins
-########################################
-
-class PersonJoiner(SQLObject):
-
- _columns = [StringCol('name', length=40, alternateID=True)]
- _joins = [RelatedJoin('AddressJoiner')]
-
-class AddressJoiner(SQLObject):
-
- _columns = [StringCol('zip', length=5, alternateID=True)]
- _joins = [RelatedJoin('PersonJoiner')]
-
-class ImplicitJoiningSO(SQLObject):
- foo = RelatedJoin('Bar')
-
-class ExplicitJoiningSO(SQLObject):
- _joins = [MultipleJoin('Bar', joinMethodName='foo')]
-
-class JoinTest(SQLObjectTest):
-
- classes = [PersonJoiner, AddressJoiner]
-
- def inserts(self):
- for n in ['bob', 'tim', 'jane', 'joe', 'fred', 'barb']:
- PersonJoiner(name=n)
- for z in ['11111', '22222', '33333', '44444']:
- AddressJoiner(zip=z)
-
- def testJoin(self):
- b = PersonJoiner.byName('bob')
- self.assertEqual(b.addressJoiners, [])
- z = AddressJoiner.byZip('11111')
- b.addAddressJoiner(z)
- self.assertZipsEqual(b.addressJoiners, ['11111'])
- self.assertNamesEqual(z.personJoiners, ['bob'])
- z2 = AddressJoiner.byZip('22222')
- b.addAddressJoiner(z2)
- self.assertZipsEqual(b.addressJoiners, ['11111', '22222'])
- self.assertNamesEqual(z2.personJoiners, ['bob'])
- b.removeAddressJoiner(z)
- self.assertZipsEqual(b.addressJoiners, ['22222'])
- self.assertNamesEqual(z.personJoiners, [])
-
- def assertZipsEqual(self, zips, dest):
- self.assertEqual([a.zip for a in zips], dest)
-
- def assertNamesEqual(self, people, dest):
- self.assertEqual([p.name for p in people], dest)
-
- def testJoinAttributeWithUnderscores(self):
- # Make sure that the implicit setting of joinMethodName works
- self.failUnless(hasattr(ImplicitJoiningSO, 'foo'))
- self.failIf(hasattr(ImplicitJoiningSO, 'bars'))
-
- # And make sure explicit setting also works
- self.failUnless(hasattr(ExplicitJoiningSO, 'foo'))
- self.failIf(hasattr(ExplicitJoiningSO, 'bars'))
-
-class PersonJoiner2(SQLObject):
-
- _columns = [StringCol('name', length=40, alternateID=True)]
- _joins = [MultipleJoin('AddressJoiner2')]
-
-class AddressJoiner2(SQLObject):
-
- _columns = [StringCol('zip', length=5),
- StringCol('plus4', length=4, default=None),
- ForeignKey('PersonJoiner2')]
- _defaultOrder = ['-zip', 'plus4']
-
-class JoinTest2(SQLObjectTest):
-
- classes = [PersonJoiner2, AddressJoiner2]
-
- def inserts(self):
- p1 = PersonJoiner2(name='bob')
- p2 = PersonJoiner2(name='sally')
- for z in ['11111', '22222', '33333']:
- a = AddressJoiner2(zip=z, personJoiner2=p1)
- #p1.addAddressJoiner2(a)
- AddressJoiner2(zip='00000', personJoiner2=p2)
-
- def test(self):
- bob = PersonJoiner2.byName('bob')
- sally = PersonJoiner2.byName('sally')
- self.assertEqual(len(bob.addressJoiner2s), 3)
- self.assertEqual(len(sally.addressJoiner2s), 1)
- bob.addressJoiner2s[0].destroySelf()
- self.assertEqual(len(bob.addressJoiner2s), 2)
- z = bob.addressJoiner2s[0]
- z.zip = 'xxxxx'
- id = z.id
- del z
- z = AddressJoiner2.get(id)
- self.assertEqual(z.zip, 'xxxxx')
-
- def testDefaultOrder(self):
- p1 = PersonJoiner2.byName('bob')
- self.assertEqual([i.zip for i in p1.addressJoiner2s],
- ['33333', '22222', '11111'])
-
-
-########################################
-## Inheritance
-########################################
-
-class Super(SQLObject):
-
- _columns = [StringCol('name', length=10)]
-
-class Sub(Super):
-
- _columns = Super._columns + [StringCol('name2', length=10)]
-
-class InheritanceTest(SQLObjectTest):
-
- classes = [Super, Sub]
-
- def testSuper(self):
- s1 = Super(name='one')
- s2 = Super(name='two')
- s3 = Super.get(s1.id)
- self.assertEqual(s1, s3)
-
- def testSub(self):
- s1 = Sub(name='one', name2='1')
- s2 = Sub(name='two', name2='2')
- s3 = Sub.get(s1.id)
- self.assertEqual(s1, s3)
-
-
-########################################
-## Expiring, syncing
-########################################
-
-class SyncTest(SQLObject):
- name = StringCol(length=50, alternateID=True, dbName='name_col')
-
-class ExpireTest(SQLObjectTest):
-
- classes = [SyncTest]
-
- def inserts(self):
- SyncTest(name='bob')
- SyncTest(name='tim')
-
- def testExpire(self):
- conn = SyncTest._connection
- b = SyncTest.byName('bob')
- conn.query("UPDATE sync_test SET name_col = 'robert' WHERE id = %i"
- % b.id)
- self.assertEqual(b.name, 'bob')
- b.expire()
- self.assertEqual(b.name, 'robert')
- conn.query("UPDATE sync_test SET name_col = 'bobby' WHERE id = %i"
- % b.id)
- b.sync()
- self.assertEqual(b.name, 'bobby')
-
-########################################
-## Validation/conversion
-########################################
-
-class SOValidation(SQLObject):
-
- name = StringCol(validator=validators.PlainText(), default='x', dbName='name_col')
- name2 = StringCol(validator=validators.ConfirmType(str), default='y')
- name3 = IntCol(validator=validators.Wrapper(fromPython=int), default=100)
-
-class ValidationTest(SQLObjectTest):
-
- classes = [SOValidation]
-
- def testValidate(self):
- t = SOValidation(name='hey')
- self.assertRaises(validators.InvalidField, setattr, t,
- 'name', '!!!')
- t.name = 'you'
-
- def testConfirmType(self):
- t = SOValidation(name2='hey')
- self.assertRaises(validators.InvalidField, setattr, t,
- 'name2', 1)
- t.name2 = 'you'
-
- def testWrapType(self):
- t = SOValidation(name3=1)
- self.assertRaises(validators.InvalidField, setattr, t,
- 'name3', 'x')
- t.name3 = 1L
- self.assertEqual(t.name3, 1)
- t.name3 = '1'
- self.assertEqual(t.name3, 1)
- t.name3 = 0
- self.assertEqual(t.name3, 0)
-
-
-########################################
-## String ID test
-########################################
-
-class SOStringID(SQLObject):
-
- _table = 'so_string_id'
- _idType = str
- val = StringCol(alternateID=True)
-
- mysqlCreate = """
- CREATE TABLE IF NOT EXISTS so_string_id (
- id VARCHAR(50) PRIMARY KEY,
- val TEXT
- )
- """
-
- postgresCreate = """
- CREATE TABLE so_string_id (
- id VARCHAR(50) PRIMARY KEY,
- val TEXT
- )
- """
-
- sybaseCreate = """
- CREATE TABLE so_string_id (
- id VARCHAR(50) UNIQUE,
- val VARCHAR(50) NULL
- )
- """
-
- firebirdCreate = """
- CREATE TABLE so_string_id (
- id VARCHAR(50) NOT NULL PRIMARY KEY,
- val BLOB SUB_TYPE TEXT
- )
- """
-
- sqliteCreate = postgresCreate
-
- mysqlDrop = """
- DROP TABLE IF EXISTS so_string_id
- """
-
- postgresDrop = """
- DROP TABLE so_string_id
- """
-
- sqliteDrop = postgresDrop
- firebirdDrop = postgresDrop
-
-class StringIDTest(SQLObjectTest):
-
- classes = [SOStringID]
-
- def testStringID(self):
- t = SOStringID(id='hey', val='whatever')
- t2 = SOStringID.byVal('whatever')
- self.assertEqual(t, t2)
- t3 = SOStringID(id='you', val='nowhere')
- t4 = SOStringID.get('you')
- self.assertEqual(t3, t4)
-
-
-
-class AnotherStyle(MixedCaseUnderscoreStyle):
- def pythonAttrToDBColumn(self, attr):
- if attr.lower().endswith('id'):
- return 'id'+MixedCaseUnderscoreStyle.pythonAttrToDBColumn(self, attr[:-2])
- else:
- return MixedCaseUnderscoreStyle.pythonAttrToDBColumn(self, attr)
-
-class SOStyleTest1(SQLObject):
- a = StringCol()
- st2 = ForeignKey('SOStyleTest2')
- _style = AnotherStyle()
-
-class SOStyleTest2(SQLObject):
- b = StringCol()
- _style = AnotherStyle()
-
-class StyleTest(SQLObjectTest):
-
- classes = [SOStyleTest2, SOStyleTest1]
-
-
- def test(self):
- st1 = SOStyleTest1(a='something', st2=None)
- st2 = SOStyleTest2(b='whatever')
- st1.st2 = st2
- self.assertEqual(st1._SO_columnDict['st2ID'].dbName, 'idst2')
- self.assertEqual(st1.st2, st2)
-
-########################################
-## Lazy updates
-########################################
-
-class Lazy(SQLObject):
-
- _lazyUpdate = True
- name = StringCol()
- other = StringCol(default='nothing')
- third = StringCol(default='third')
-
-class LazyTest(SQLObjectTest):
-
- classes = [Lazy]
-
- def setUp(self):
- # All this stuff is so that we can track when the connection
- # does an actual update; we put in a new _SO_update method
- # that calls the original and sets an instance variable that
- # we can later check.
- SQLObjectTest.setUp(self)
- self.conn = Lazy._connection
- self.conn.didUpdate = False
- self._oldUpdate = self.conn._SO_update
- newUpdate = lambda so, values, s=self, c=self.conn, o=self._oldUpdate: self._alternateUpdate(so, values, c, o)
- self.conn._SO_update = newUpdate
-
- def tearDown(self):
- self.conn._SO_update = self._oldUpdate
- del self._oldUpdate
-
- def _alternateUpdate(self, so, values, conn, oldUpdate):
- conn.didUpdate = True
- return oldUpdate(so, values)
-
- def test(self):
- assert not self.conn.didUpdate
- obj = Lazy(name='tim')
- # We just did an insert, but not an update:
- assert not self.conn.didUpdate
- obj.set(name='joe')
- assert obj.dirty
- self.assertEqual(obj.name, 'joe')
- assert not self.conn.didUpdate
- obj.syncUpdate()
- self.assertEqual(obj.name, 'joe')
- assert self.conn.didUpdate
- assert not obj.dirty
- self.assertEqual(obj.name, 'joe')
- self.conn.didUpdate = False
-
- obj = Lazy(name='frank')
- obj.name = 'joe'
- assert not self.conn.didUpdate
- assert obj.dirty
- self.assertEqual(obj.name, 'joe')
- obj.name = 'joe2'
- assert not self.conn.didUpdate
- assert obj.dirty
- self.assertEqual(obj.name, 'joe2')
- obj.syncUpdate()
- self.assertEqual(obj.name, 'joe2')
- assert not obj.dirty
- assert self.conn.didUpdate
- self.conn.didUpdate = False
-
- obj = Lazy(name='loaded')
- assert not obj.dirty
- assert not self.conn.didUpdate
- self.assertEqual(obj.name, 'loaded')
- obj.name = 'unloaded'
- assert obj.dirty
- self.assertEqual(obj.name, 'unloaded')
- assert not self.conn.didUpdate
- obj.sync()
- assert not obj.dirty
- self.assertEqual(obj.name, 'unloaded')
- assert self.conn.didUpdate
- self.conn.didUpdate = False
- obj.name = 'whatever'
- assert obj.dirty
- self.assertEqual(obj.name, 'whatever')
- assert not self.conn.didUpdate
- obj._SO_loadValue('name')
- assert obj.dirty
- self.assertEqual(obj.name, 'whatever')
- assert not self.conn.didUpdate
- obj._SO_loadValue('other')
- self.assertEqual(obj.name, 'whatever')
- assert not self.conn.didUpdate
- obj.syncUpdate()
- assert self.conn.didUpdate
- self.conn.didUpdate = False
-
- # Now, check that get() doesn't screw
- # cached objects' validator state.
- obj_id = obj.id
- old_state = obj._SO_validatorState
- obj = Lazy.get(obj_id)
- assert not obj.dirty
- assert not self.conn.didUpdate
- assert obj._SO_validatorState is old_state
- self.assertEqual(obj.name, 'whatever')
- obj.name = 'unloaded'
- self.assertEqual(obj.name, 'unloaded')
- assert obj.dirty
- assert not self.conn.didUpdate
- # Fetch the object again with get() and
- # make sure dirty is still set, as the
- # object should come from the cache.
- obj = Lazy.get(obj_id)
- assert obj.dirty
- assert not self.conn.didUpdate
- self.assertEqual(obj.name, 'unloaded')
- obj.syncUpdate()
- assert self.conn.didUpdate
- assert not obj.dirty
- self.conn.didUpdate = False
-
- # Then clear the cache, and try a get()
- # again, to make sure stuf like _SO_createdValues
- # is properly initialized.
- self.conn.cache.clear()
- obj = Lazy.get(obj_id)
- assert not obj.dirty
- assert not self.conn.didUpdate
- self.assertEqual(obj.name, 'unloaded')
- obj.name = 'spongebob'
- self.assertEqual(obj.name, 'spongebob')
- assert obj.dirty
- assert not self.conn.didUpdate
- obj.syncUpdate()
- assert self.conn.didUpdate
- assert not obj.dirty
- self.conn.didUpdate = False
-
- obj = Lazy(name='last')
- assert not obj.dirty
- obj.syncUpdate()
- assert not self.conn.didUpdate
- assert not obj.dirty
- # Check that setting multiple values
- # actually works. This was broken
- # and just worked because we were testing
- # only one value at a time, so 'name'
- # had the right value after the for loop *wink*
- # Also, check that passing a name that is not
- # a valid column doesn't break, but instead
- # just does a plain setattr.
- obj.set(name='first', other='who',
- third='yes', driver='james')
- self.assertEqual(obj.name, 'first')
- self.assertEqual(obj.other, 'who')
- self.assertEqual(obj.third, 'yes')
- self.assertEqual(obj.driver, 'james')
- assert obj.dirty
- assert not self.conn.didUpdate
- obj.syncUpdate()
- assert self.conn.didUpdate
- assert not obj.dirty
-
-
-########################################
-## Indexes
-########################################
-
-class SOIndex1(SQLObject):
- name = StringCol(length=100)
- number = IntCol()
-
- nameIndex = DatabaseIndex('name', unique=True)
- nameIndex2 = DatabaseIndex(name, number)
- nameIndex3 = DatabaseIndex({'column': name,
- 'length': 3})
-
-class SOIndex2(SQLObject):
-
- name = StringCol()
-
- nameIndex = DatabaseIndex({'expression': 'lower(name)'})
-
-class IndexTest1(SQLObjectTest):
-
- classes = [SOIndex1]
-
- def test(self):
- n = 0
- for name in 'blah blech boring yep yort snort'.split():
- n += 1
- SOIndex1(name=name, number=n)
- mod = SOIndex1._connection.module
- try:
- SOIndex1(name='blah', number=0)
- except (mod.ProgrammingError, mod.IntegrityError):
- # expected
- pass
- else:
- assert 0, "Exception expected."
-
-class IndexTest2(SQLObjectTest):
-
- classes = [SOIndex2]
-
- requireSupport = ('supportExpressionIndex',)
-
- def test(self):
- # Not much to test, just want to make sure the table works
- # properly
- if not self.hasSupport():
- return
- SOIndex2(name='')
-
-
-########################################
-## Distinct
-########################################
-
-class Distinct1(SQLObject):
- n = IntCol()
-
-class Distinct2(SQLObject):
- other = ForeignKey('Distinct1')
-
-class DistinctTest(SQLObjectTest):
-
- classes = [Distinct1, Distinct2]
-
- def inserts(self):
- obs = [Distinct1(n=i) for i in range(3)]
- Distinct2(other=obs[0])
- Distinct2(other=obs[0])
- Distinct2(other=obs[1])
-
- def count(self, select):
- result = {}
- for ob in select:
- result[int(ob.n)] = result.get(int(ob.n), 0)+1
- return result
-
- def testDistinct(self):
- query = (Distinct2.q.otherID==Distinct1.q.id)
- sel = Distinct1.select(query)
- self.assertEqual(self.count(sel),
- {0: 2, 1: 1})
- sel = Distinct1.select(query, distinct=True)
- self.assertEqual(self.count(sel),
- {0: 1, 1:1})
-
-########################################
-## Run from command-line:
-########################################
-
-def coverModules():
- sys.stdout.write('Writing coverage...')
- sys.stdout.flush()
- here = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- from SQLObject import DBConnection as tmp
- there = os.path.dirname(os.path.abspath(tmp.__file__))
- for name, mod in sys.modules.items():
- if not mod:
- continue
- try:
- modFile = os.path.abspath(mod.__file__)
- except AttributeError:
- # Probably a C extension
- continue
- if modFile.startswith(here) or modFile.startswith(there):
- writeCoverage(mod, there, os.path.join(here, 'SQLObject'))
- coverage.erase()
- sys.stdout.write('done.\n')
-
-
-def writeCoverage(module, oldBase, newBase):
- filename, numbers, unexecuted, s = coverage.analysis(module)
- coverFilename = filename + ',cover'
- if coverFilename.startswith(oldBase):
- coverFilename = newBase + coverFilename[len(oldBase):]
- fout = open(coverFilename, 'w')
- fin = open(filename)
- i = 1
- lines = 0
- good = 0
- while 1:
- line = fin.readline()
- if not line: break
- assert line[-1] == '\n'
- fout.write(line[:-1])
- unused = i in unexecuted
- interesting = interestingLine(line, unused)
- if interesting:
- if unused:
- fout.write(' '*(72-len(line)))
- fout.write('#@@@@')
- lastUnused = True
- else:
- lastUnused = False
- good += 1
- lines += 1
- fout.write('\n')
- i += 1
- fout.write('\n# Coverage:\n')
- fout.write('# %i/%i, %i%%' % (
- good, lines, lines and int(good*100/lines)))
- fout.close()
- fin.close()
-
-def interestingLine(line, unused):
- line = line.strip()
- if not line:
- return False
- if line.startswith('#'):
- return False
- if line in ('"""', '"""'):
- return False
- if line.startswith('global '):
- return False
- if line.startswith('def ') and not unused:
- # If a def *isn't* executed, that's interesting
- return False
- if line.startswith('class ') and not unused:
- return False
- return True
-
-
-def main():
- import unittest
- from getopt import getopt, GetoptError
-
- try:
- options, arguments = getopt(sys.argv[1:], "d:v",
- ["database=", "extra-verbose", "super-verbose",
- "inserts", "coverage"])
- except GetoptError:
- usage(1)
-
- dbs = []
- newArgs = []
- doCoverage = False
- verbose = 0
-
- for option, value in options:
- if option in ('-d', '--database'):
- dbs.append(value)
- elif option == '--inserts':
- SQLObjectTest.debugInserts = True
- elif option == '--coverage':
- # Handled earlier, so we get better coverage
- doCoverage = True
- elif option == '--extra-verbose':
- verbose = 1
- elif option == '--super-verbose':
- verbose = 2
- elif option == '-v':
- verbose += 1
-
- if verbose >= 1:
- SQLObjectTest.debugSQL = True
- if verbose >= 2:
- SQLObjectTest.debugOutput = True
- newArgs.append('-vv')
- newArgs.extend(arguments)
-
- sys.argv = [sys.argv[0]] + newArgs
- if not dbs:
- dbs = ['mysql']
- if dbs == ['all']:
- dbs = supportedDatabases()
- for db in dbs:
- print 'Testing %s' % db
- curr_db = db
- setDatabaseType(db)
- try:
- unittest.main()
- except SystemExit:
- pass
- if doCoverage:
- coverage.stop()
- coverModules()
-
-if __name__ == '__main__':
- main()
Copied: trunk/SQLObject/tests/test_sqlobject.py (from rev 415, trunk/SQLObject/tests/test.py)
|
|
From: <sub...@co...> - 2004-11-29 19:10:14
|
Author: phd
Date: 2004-11-29 19:10:10 +0000 (Mon, 29 Nov 2004)
New Revision: 415
Modified:
trunk/SQLObject/tests/test.py
Log:
Separated main() to use it in other test modules.
Used getopt to parse options and arguments.
Modified: trunk/SQLObject/tests/test.py
===================================================================
--- trunk/SQLObject/tests/test.py 2004-11-29 16:07:00 UTC (rev 414)
+++ trunk/SQLObject/tests/test.py 2004-11-29 19:10:10 UTC (rev 415)
@@ -1,5 +1,5 @@
"""
-Main (um, only) unit testing for SQLObject.
+Main unit testing for SQLObject.
Use -vv to see SQL queries, -vvv to also see output from queries,
and together with --inserts to see the SQL from the standard
@@ -8,7 +8,7 @@
from __future__ import generators
-import sys
+import sys, os
if '--coverage' in sys.argv:
import coverage
print 'Starting coverage'
@@ -1330,42 +1330,54 @@
return False
return True
-if __name__ == '__main__':
- import unittest, sys, os
+
+def main():
+ import unittest
+ from getopt import getopt, GetoptError
+
+ try:
+ options, arguments = getopt(sys.argv[1:], "d:v",
+ ["database=", "extra-verbose", "super-verbose",
+ "inserts", "coverage"])
+ except GetoptError:
+ usage(1)
+
dbs = []
newArgs = []
doCoverage = False
- for arg in sys.argv[1:]:
- if arg.startswith('-d'):
- dbs.append(arg[2:])
- continue
- if arg.startswith('--database='):
- dbs.append(arg[11:])
- continue
- if arg in ('-vv', '--extra-verbose'):
- SQLObjectTest.debugSQL = True
- if arg in ('-vvv', '--super-verbose'):
- SQLObjectTest.debugSQL = True
- SQLObjectTest.debugOutput = True
- newArgs.append('-vv')
- continue
- if arg in ('--inserts',):
+ verbose = 0
+
+ for option, value in options:
+ if option in ('-d', '--database'):
+ dbs.append(value)
+ elif option == '--inserts':
SQLObjectTest.debugInserts = True
- continue
- if arg in ('--coverage',):
+ elif option == '--coverage':
# Handled earlier, so we get better coverage
doCoverage = True
- continue
- newArgs.append(arg)
+ elif option == '--extra-verbose':
+ verbose = 1
+ elif option == '--super-verbose':
+ verbose = 2
+ elif option == '-v':
+ verbose += 1
+
+ if verbose >= 1:
+ SQLObjectTest.debugSQL = True
+ if verbose >= 2:
+ SQLObjectTest.debugOutput = True
+ newArgs.append('-vv')
+ newArgs.extend(arguments)
+
sys.argv = [sys.argv[0]] + newArgs
if not dbs:
dbs = ['mysql']
if dbs == ['all']:
dbs = supportedDatabases()
for db in dbs:
+ print 'Testing %s' % db
curr_db = db
setDatabaseType(db)
- print 'Testing %s' % db
try:
unittest.main()
except SystemExit:
@@ -1374,3 +1386,5 @@
coverage.stop()
coverModules()
+if __name__ == '__main__':
+ main()
|
|
From: <sub...@co...> - 2004-11-29 16:07:03
|
Author: ianb
Date: 2004-11-29 16:07:00 +0000 (Mon, 29 Nov 2004)
New Revision: 414
Modified:
trunk/SQLObject/sqlobject/main.py
Log:
Was invalidly converting values to database representation, then putting
them in the Python-representation attribute. Per email Re: [SQLObject]
.set() fromPython
Modified: trunk/SQLObject/sqlobject/main.py
===================================================================
--- trunk/SQLObject/sqlobject/main.py 2004-11-29 16:05:52 UTC (rev 413)
+++ trunk/SQLObject/sqlobject/main.py 2004-11-29 16:07:00 UTC (rev 414)
@@ -770,7 +770,7 @@
for name, value in kw.items():
fromPy = getattr(self, '_SO_fromPython_%s' % name, None)
if fromPy:
- kw[name] = value = fromPy(value, self._SO_validatorState)
+ kw[name] = dbValue = fromPy(value, self._SO_validatorState)
setattr(self, instanceName(name), value)
for name, value in extra.items():
setattr(self, name, value)
|
|
From: <sub...@co...> - 2004-11-29 16:05:56
|
Author: ianb
Date: 2004-11-29 16:05:52 +0000 (Mon, 29 Nov 2004)
New Revision: 413
Modified:
trunk/SQLObject/tests/test.py
Log:
ClassRegistryTest: Error string for duplicate classes changed
IndexTest1: Postgres raises ProgrammingError instead of
IntegrityError, sometimes; just catches either now.
Modified: trunk/SQLObject/tests/test.py
===================================================================
--- trunk/SQLObject/tests/test.py 2004-11-29 12:21:59 UTC (rev 412)
+++ trunk/SQLObject/tests/test.py 2004-11-29 16:05:52 UTC (rev 413)
@@ -34,7 +34,7 @@
class Duplicate(SQLObject):
pass
except ValueError, err:
- self.assertEqual(str(err), "class Duplicate is already in the registry")
+ assert str(err).startswith("class Duplicate is already in the registry")
else:
self.fail("should have raised an error on duplicate class definition")
@@ -1198,14 +1198,9 @@
n += 1
SOIndex1(name=name, number=n)
mod = SOIndex1._connection.module
- # Firebird doesn't throw an integrity error, unfortunately:
- if mod.__name__.endswith('kinterbasdb'):
- exc = mod.ProgrammingError
- else:
- exc = mod.IntegrityError
try:
SOIndex1(name='blah', number=0)
- except exc:
+ except (mod.ProgrammingError, mod.IntegrityError):
# expected
pass
else:
|
|
From: <sub...@co...> - 2004-11-12 05:20:30
|
Author: ianb Date: 2004-11-11 09:33:25 -0500 (Thu, 11 Nov 2004) New Revision: 349 Added: trunk/SQLObject/docs/presentation-2004-11/ trunk/SQLObject/docs/presentation-2004-11/sqlobject-and-database-progr= amming.html trunk/SQLObject/docs/presentation-2004-11/ui/ trunk/SQLObject/docs/presentation-2004-11/ui/bodybg.gif trunk/SQLObject/docs/presentation-2004-11/ui/custom.css trunk/SQLObject/docs/presentation-2004-11/ui/framing.css trunk/SQLObject/docs/presentation-2004-11/ui/opera.css trunk/SQLObject/docs/presentation-2004-11/ui/pretty.css trunk/SQLObject/docs/presentation-2004-11/ui/print.css trunk/SQLObject/docs/presentation-2004-11/ui/s5-core.css trunk/SQLObject/docs/presentation-2004-11/ui/slides.css trunk/SQLObject/docs/presentation-2004-11/ui/slides.js Log: A presentation I'm giving Added: trunk/SQLObject/docs/presentation-2004-11/sqlobject-and-database-p= rogramming.html =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/sqlobject-and-database-prog= ramming.html 2004-11-11 14:12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/sqlobject-and-database-prog= ramming.html 2004-11-11 14:33:25 UTC (rev 349) @@ -0,0 +1,769 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"=20 + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns=3D"http://www.w3.org/1999/xhtml"> + +<head> +<title>SQLObject and Database Programming in Python</title> +<meta name=3D"version" content=3D"S5 1.0" /> +<link rel=3D"stylesheet" href=3D"ui/slides.css" type=3D"text/css" media=3D= "projection" id=3D"slideProj" /> +<link rel=3D"stylesheet" href=3D"ui/opera.css" type=3D"text/css" media=3D= "projection" id=3D"operaFix" /> +<link rel=3D"stylesheet" href=3D"ui/print.css" type=3D"text/css" +media=3D"print" id=3D"slidePrint" /> +<link rel=3D"stylesheet" href=3D"ui/custom.css" type=3D"text/css"/> +<sc ript src=3D"ui/slides.js" type=3D"text/javascript"></script> +</head> +<body> + +<div class=3D"layout"> + +<div id=3D"currentSlide"></div> +<div id=3D"header"></div> +<div id=3D"footer"> +<h1>ChiPy, 11 November 2004</h1> +<h2>SQLObject and Database Programming in Python</h2> +<div id=3D"controls"></div> +</div> + +</div> + + +<div class=3D"presentation"> + +<div class=3D"slide"> +<h1>SQLObject and Database Programming in Python</h1> +<h3>Ian Bicking</h3> +<h4>Imaginary Landscape</h4> +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>The Ongoing Example</h1> + +<h2>Address book:</h2> +<p> +<ul> + <li><code>person</code>: + <ul> + <li><code>first_name</code></li> + <li><code>last_name</code></li> + <li><code>email</code> (many emails for one person)</li> + </ul></li> + <li><code>email</code>: + <ul> + <li><code>type</code></li> + <li><code>address</code></li> + </ul></li> +</ul> +</p> +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Database Programming in Python</h1> + +<p>Database programming in Python is based on the <b><a +href=3D"http://www.python.org/peps/pep-0249.html">DB-API</a></b>. +Some supported databases: + +<ul> +<li>MySQL</li> +<li>PostgreSQL (multiple drivers)</li> +<li>SQLite</li> +<li>Oracle</li> +<li>Sybase</li> +<li>Firebird (Interbase)</li> +<li>MAXDB (SAP DB)</li> +<li>MS SQL Server</li> +</p> +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>DB API Example</h1> + +<p> +Example: + +<pre> +import MySQLdb +conn =3D MySQLdb.connect( + db=3D<span class=3D"string">'test'</span>, username=3D<span class=3D= "string">'ianb'</span>) +cur =3D conn.cursor() +cur.execute( + <span class=3D"sql">"SELECT id, first_name, last_name FROM person"</= span>) +result =3D cur.fetchall() +for id, first_name, last_name in result: + print <span class=3D"string">"%2i %s, %s"</span> % (id, last_name, f= irst_name) +</pre> + +</p> +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>DB API</h1> + +<ul> +<li> Import the databse module (<code>MySQLdb</code>, +<code>psycopg</code>, <code>sqlite</code>, etc) </li> +<li> Use <code>module.connect(...)</code> to create a +connection. </li> +<li> Use <code>connection.cursor()</code> to get a cursor. Cursors do +all the work. </li> +<li> Use <code>cursor.execute(sql_query)</code> to run +something. </li> +<li> Use <code>cursor.fetchall()</code> to get results. </li>=20 + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>DB API problems</h1> + +<ol> +<li> Connections and cursors are tedious. </li> +<li> The databases don't all work the same; multiple SQL +dialects. </li> +<li> Lots of time spent writing SQL. </li> +<li> Database updates can effect all the SQL you've written. </li> +<li> Unless you make abstractions... </li> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Abstractions</h1> + +<p> +<ul> +<li> Every significant database application has a database abstraction +layer. </li> +<li> You write one whether you mean to or not. </li> +</p> + +</div> + + + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Object-Relational Mappers</h1> + +<p> + +The table: + +<table border=3D1> + +<tr><th colspan=3D3>person</th></tr> + +<tr> + <th>id</th> + <th>first_name</th> + <th>last_name</th> +</tr> + +<tr> + <td>1</td> + <td>John</td> + <td>Doe</td> +</tr> +<tr> + <td>2</td> + <td>Tom</td> + <td>Jones</td> +</tr> +<tr> + <td colspan=3D3 align=3Dcenter>...</td> +</tr> +</table> + +<p> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> + +<h1>Object-Relational Mappers: Classes</h1> + +<p> + +The class: + +<table border=3D1> + +<tr class=3D"code-accent"><th colspan=3D3>person</th></tr> + +<tr class=3D"code-accent"> + <th>id</th> + <th>first_name</th> + <th>last_name</th> +</tr> + +<tr> + <td>1</td> + <td>John</td> + <td>Doe</td> +</tr> +<tr> + <td>2</td> + <td>Tom</td> + <td>Jones</td> +</tr> +<tr> + <td colspan=3D3 align=3Dcenter>...</td> +</tr> + +</table> +<p> + +<pre> +class Person(SQLObject): + <span class=3D"comment"># id is implicit</span> + first_name =3D StringCol() + last_name =3D StringCol() +</pre> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> + +<h1>Object-Relational Mappers: Instances</h1> + +<p> + +An instance: + +<table border=3D1> + +<tr><th colspan=3D3>person</th></tr> + +<tr> + <th>id</th> + <th>first_name</th> + <th>last_name</th> +</tr> + +<tr class=3D"code-accent"> + <td>1</td> + <td>John</td> + <td>Doe</td> +</tr> +<tr> + <td>2</td> + <td>Tom</td> + <td>Jones</td> +</tr> +<tr> + <td colspan=3D3 align=3Dcenter>...</td> +</tr> + +</table> +<p> + +<pre> +john =3D Person.get(1) +assert john.first_name =3D=3D <span class=3D"string">'John'</span> +</pre> + + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Object-Relational Mapping: summary</h1> + +<ul> + <li>Every table is a class</li> + <li>Every row is an instance</li> + <li>Columns become attributes</li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Usage</h1> + +<pre> +__connection__ =3D <span class=3D"string">'postgres://pgsql@localhost/te= st'</span> +class Person(SQLObject): + first_name =3D StringCol() + last_name =3D StringCol() + emails =3D MultipleJoin('Email') +class Email(SQLObject): + person =3D ForeignKey(<span class=3D"string">'Person'</span>) + type =3D EnumCol(['home', 'work']) + address =3D StringCol() +def createTables(): + for table in (Person, Email): + table.createTable(ifNotExists=3DTrue) +</pre> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>More use...</h1> + +Using your classes: + +<pre> +<span class=3D"prompt">>>></span> john =3D Person(first_name=3D= <span class=3D"string">'John'</span>, last_name=3D<span class=3D"string">= 'Doe'</span>) +<span class=3D"prompt">>>></span> email =3D Email(person=3Djohn= , type=3D<span class=3D"string">'home'</span>,=20 +<span class=3D"prompt">...</span> address=3D<span class=3D"string">'= jo...@wo...'</span>) +<span class=3D"prompt">>>></span> john.emails +<span class=3D"output">[]</span> +<span class=3D"prompt">>>></span> tom =3D Person(first_name=3D<= span class=3D"string">'Tom'</span>, last_name=3D<span class=3D"string">'J= ones'</span>) +<span class=3D"prompt">>>></span> tom is Person.get(tom.id) +<span class=3D"output">True</span> +<span class=3D"prompt">>>></span> list(Person.selectBy(first_na= me=3D<span class=3D"string">'John'</span>)) +<span class=3D"output">[]</span> +</pre> + +</div> + + + + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Defining Classes</h1> + +<ul> + <li> The class name matches the table name </li> + <li> The attributes match the column names </li> + <li> (kind of...) </li> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Defining Classes...</h1> + +<p> +You can add extra methods: + +<pre> +class Person(SQLObject): + ... + def _get_name(self): + return self.first_name + ' ' + self.last_name +</pre> + + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1></h1> + +<ul> +<li> <code>_get_attr()</code> methods are called whenever the +<code>obj.attr</code> attribute is called </li> +<li> <code>_set_attr()</code> methods are called whenever the +<code>obj.attr =3D value</code> statement is run </li> +<li> <code>_set_attr()</code> is optional </li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Defining classes...</h1> + +<p> +You can override columns: + +<pre> +class Person(SQLObject): + ... + last_name_searchable =3D StringCol() + def _set_last_name(self, value): + self._SO_set_last_name(self, value) + self.last_name_lower =3D re.sub(<span class=3D"string">r'[^a-zA-= Z]'</span>, <span class=3D"string">''</span>, value).lower() +</pre> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Defining classes...</h1> + +<p> +You can fiddle with the naming: + +<pre> +class Person(SQLObject): + _table =3D <span class=3D"string">"people"</span> + first_name =3D StringCol(dbName=3D<span class=3D"string">"fname"</sp= an>) + ... +</pre> + +</p> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Connecting classes</h1> + +<p> +Foreign Keys: + +<pre> +class Email(SQLObject): + person =3D ForeignKey(<span class=3D"string">'Person'</span>) + ... +</pre> + +Note we use a string for <code class=3D"string">'Person'</code>. + + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Backreferences</h1> + +<p> +The other side of one-to-many: + +<pre> +class Person(SQLObject): + ... + emails =3D MultipleJoin(<span class=3D"string">'Email'</span>) +</pre> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Many-to-many</h1> + +<p> +Many to many relationships imply a "hidden" table: + +<pre> +class Address(SQLObject): + people =3D RelatedJoin(<span class=3D"string">'Person'</span>) + ... +class Person(SQLObject): + addresses =3D RelatedJoin(<span class=3D"string">'Address'</span>) +</pre> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Lazy classes</h1> + +<p> +SQLObject can use reflection to figure out what columns your table +has: + +<pre> +class Person(SQLObject): + _fromDatabase =3D True +</pre> + +</p> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Many-to-many...</h1> + +<p> +The intermediate table created: + +<pre> +CREATE TABLE address_person ( + address_id INT NOT NULL, + person_id INT NOT NULL +); +</pre> +</p> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Instances</h1> + +<ul> +<li>Use <code>Person.get(id)</code> to retrieve a row</li> +<li>Use <code>Person(first_name=3D...)</code> to insert a row (the=20 +new object is returned)</li> +<li>Use <code>aPerson.destroySelf()</code> to delete a row</li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Updating</h1> + +<ul> +<li>Use <code>aPerson.first_name =3D <span +class=3D"string">"new_name"</span></code></li> +<li>Use <code>aPerson.set(first_name=3D<span +class=3D"string">"new_fname"</span>, last_name=3D<span +class=3D"string">"new_lname"</span>)</code> for multiple simultaneous +updates. </li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Selecting</h1> + +<p> +You can use Python expressions (kind of): + +<pre> +query =3D Person.q.first_name =3D=3D <span class=3D"string">"Joe"</span> +Person.select(query) +</pre> + +</p> + + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Selecting...</h1> + +<p> + +<ul> +<li><code>Class.<b>q</b>.<i>column_name</i></code> creates a magical +object that creates queries.</li> +<li><code>sqlrepr()</code> turns these query objects into SQL (mostly +hidden)</li> +<li><code>sqlrepr(Person.q.first_name =3D=3D <span +class=3D"string">"Joe"</span>, <span class=3D"string">'mysql')</code> +creates the SQL <code class=3D"sql">person.first_name =3D +'Joe'</code></li> + +</p> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Selecting...</h1> + +<p> +Complicated joins are possible: + +<pre> +Person.select((Person.q.id =3D=3D Email.q.personID) + & (Email.q.address.startswith('joe'))) +</pre> + +Becomes: + +<pre> +SELECT person.id, person.first_name, person.last_name +FROM person, email +WHERE person.id =3D email.person_id + AND email.address LIKE 'joe%' +</pre> + +</p> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>SelectResult</h1> + +Select results are fancy. + +<ul> +<li> You can slice them, and <code class=3D"sql">LIMIT</code> and <code +class=3D"sql">OFFSET</code> statements are added to your query</li> +<li> You can iterate through them, and avoid loading all objects into +memory</li> +<li> You can do things like <code>select_result.count()</code> to run +aggregate functions </li> +<li> To get a real list, you must do <code>list(select_result)</code></l= i> + +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Caching</h1> + +<ul> +<li>SQLObject caches everything</li> +<li>Maybe too much (bad if you have multiple updaters)</li> +<li>Needs to because there's no joins</li> +<li>Has potential to be faster than ad hoc queries</li> +<li>Thread safety or thread confusion?</li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>Performance</h1> + +<ul> +<li> Not good if you are dealing with lots and lots of rows </li> +<li> Inserts and selects substantially slower </li> +<li> But for many applications you'll pay that price sooner or later +anyway </li> +</ul> + +</div> + + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Solving the question by avoidance</h1> + +<ul> + <li> SQLObject doesn't let you forget SQL </li> + <li> You still have to think relationally </li> + <li> But many relational concepts don't work either </li> + <li> Advantage: it's easy </li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>ORM Mismatch</h1> + +<ul> + <li> Python classes aren't tables</li> + <li> Python instances aren't rows</li> + <li> Primitive values (like <code class=3D"string">"John"</code>) + aren't part of the ORM at all </li> +<ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>ORM Mismatch: Classes</h1> + +<ul> + <li> Databases don't have inheritance </li> + <li> Even when they do, no one uses it </li> + <li> Some tables are too boring (e.g., intermediate tables for + many-to-many relationships) </li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + +<div class=3D"slide"> +<h1>ORM Mismatch: Instances</h1> + +<ul> + <li> Instances get garbage collected, rows are forever </li> + <li> Instances can't be pre-allocated </li> + <li> In the relational calculus, rows don't have real identity </li> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>ORM Mismatch: Relations</h1> + +<ul> + <li> Things like joins don't make sense for objects, but are central + to relations </li> + <li> Views and stored procedures also don't make sense </li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + +<div class=3D"slide"> +<h1>Solving the Mismatch</h1> + +SQLObject's answer: don't try too hard. + +<ul> + <li> There exist database restrictions; not every database schema maps + well. (But most are fine) </li> + <li> There exist object restrictions; not every object-oriented + concept maps well; e.g., no inheritance. </li> +</ul> + +</div> + +<!-- =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --> + + + +</div> + +</body> +</html> Added: trunk/SQLObject/docs/presentation-2004-11/ui/bodybg.gif =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D (Binary files differ) Property changes on: trunk/SQLObject/docs/presentation-2004-11/ui/bodybg.= gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/SQLObject/docs/presentation-2004-11/ui/custom.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/custom.css 2004-11-11 14= :12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/custom.css 2004-11-11 14= :33:25 UTC (rev 349) @@ -0,0 +1,39 @@ +.string {=20 + color: #006600; +} + +.comment {=20 + color: #993300; +} + +.output {=20 + font-weight: bold; + color: #000066; +} + +.prompt {=20 + color: #000000; +} + +.sql {=20 + color: #006600; + font-weight: bold; +} + +code {=20 + color: #000066; + padding-left: 3px; + padding-right: 3px; + font-weight: bold; +} + +pre {=20 + margin-left: 7px; + padding: 3px; + border-left: 4px solid #666666; + background-color: #eeeeee; +} + +tr.code-accent td, tr.code-accent th {=20 + border: medium green dashed; +} \ No newline at end of file Added: trunk/SQLObject/docs/presentation-2004-11/ui/framing.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/framing.css 2004-11-11 1= 4:12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/framing.css 2004-11-11 1= 4:33:25 UTC (rev 349) @@ -0,0 +1,23 @@ +/* The following styles size, place, and layer the slide components. + Edit these if you want to change the overall slide layout. + The commented lines can be uncommented (and modified, if necessary)=20 + to help you with the rearrangement process. */ + +div#header, div#footer, div.slide {width: 100%; top: 0; left: 0;} +div#header {top: 0; height: 3em; z-index: 1;} +div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;} +div.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2;} +div#controls {left: 50%; top: 0; width: 50%; height: 100%; z-index: 1;} +#footer>div#controls {bottom: 0; top: auto; height: auto;} + +div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; + margin: 0;} +#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z= -index: 10;} +html>body #currentSlide {position: fixed;} + +/* +div#header {background: #FCC;} +div#footer {background: #CCF;} +div#controls {background: #BBD;} +div#currentSlide {background: #FFC;} +*/ Added: trunk/SQLObject/docs/presentation-2004-11/ui/opera.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/opera.css 2004-11-11 14:= 12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/opera.css 2004-11-11 14:= 33:25 UTC (rev 349) @@ -0,0 +1,7 @@ +/* DO NOT CHANGE THESE unless you really want to break Opera Show */ +div.slide { + visibility: visible !important; + position: static !important; + page-break-before: always; +} +#slide0 {page-break-before: avoid;} Added: trunk/SQLObject/docs/presentation-2004-11/ui/pretty.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/pretty.css 2004-11-11 14= :12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/pretty.css 2004-11-11 14= :33:25 UTC (rev 349) @@ -0,0 +1,74 @@ +/* Following are the presentation styles -- edit away! + Note that the 'body' font size may have to be changed if the resoluti= on is + different than expected. */ + +body {background: #fff url(bodybg.gif) -16px 0 no-repeat; color: #000; f= ont-size: 2em;} +:link, :visited {text-decoration: none;} +#controls :active {color: #88A !important;} +#controls :focus {outline: 1px dotted #227;} +h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inh= erit;} +ul, pre {margin: 0; line-height: 1em;} +html, body {margin: 0; padding: 0;} + +blockquote, q {font-style: italic;} +blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: cen= ter; font-size: 1em;} +blockquote p {margin: 0;} +blockquote i {font-style: normal;} +blockquote b {display: block; margin-top: 0.5em; font-weight: normal; fo= nt-size: smaller; font-style: normal;} +blockquote b i {font-style: italic;} + +kbd {font-weight: bold; font-size: 1em;} +sup {font-size: smaller; line-height: 1px;} + +code {padding: 2px 0.25em; font-weight: bold; color: #533;} +code.bad, code del {color: red;} +code.old {color: silver;} +pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 9= 0%;} +pre code {display: block;} +ul {margin-left: 5%; margin-right: 7%; list-style: disc;} +li {margin-top: 0.75em; margin-right: 0;} +ul ul {line-height: 1;} +ul ul li {margin: .2em; font-size: 85%; list-style: square;} +img.leader {display: block; margin: 0 auto;} + +div#header, div#footer {background: #005; color: #AAB; + font-family: Verdana, Helvetica, sans-serif;} +div#header {background: #005 url(bodybg.gif) -16px 0 no-repeat; + line-height: 1px;} +div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;} +#footer h1, #footer h2 {display: block; padding: 0 1em;} +#footer h2 {font-style: italic;} + +div.long {font-size: 0.75em;} +.slide h1 {position: absolute; top: 0.7em; left: 87px; z-index: 1; + margin: 0; padding: 0.3em 0 0 50px; white-space: nowrap; + font: bold 150%/1em Helvetica, sans-serif; text-transform: capitalize; + color: #DDE; background: #005;} +.slide h3 {font-size: 130%;} +h1 abbr {font-variant: small-caps;} + +div#controls {position: absolute; z-index: 1; left: 50%; top: 0; + width: 50%; height: 100%; + text-align: right;} +#footer>div#controls {position: fixed; bottom: 0; padding: 1em 0; + top: auto; height: auto;} +div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; + margin: 0; padding: 0;} +div#controls a {font-size: 2em; padding: 0; margin: 0 0.5em;=20 + background: #005; border: none; color: #779;=20 + cursor: pointer;} +div#controls select {visibility: hidden; background: #DDD; color: #227;} +div#controls div:hover select {visibility: visible;} + +#currentSlide {text-align: center; font-size: 0.5em; color: #449;} + +#slide0 {padding-top: 3.5em; font-size: 90%;} +#slide0 h1 {position: static; margin: 1em 0 1.33em; padding: 0; + font: bold 2em Helvetica, sans-serif; white-space: normal; + color: #000; background: transparent;} +#slide0 h3 {margin-top: 0.5em; font-size: 1.5em;} +#slide0 h4 {margin-top: 0; font-size: 1em;} + +ul.urls {list-style: none; display: inline; margin: 0;} +.urls li {display: inline; margin: 0;} +.note {display: none;} Added: trunk/SQLObject/docs/presentation-2004-11/ui/print.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/print.css 2004-11-11 14:= 12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/print.css 2004-11-11 14:= 33:25 UTC (rev 349) @@ -0,0 +1 @@ +/* The next rule is necessary to have all slides appear in print! DO NOT= REMOVE IT! */=0Ddiv.slide, ul {page-break-inside: avoid; visibility: vis= ible !important;}=0Dh1 {page-break-after: avoid;}=0D=0Dbody {font-size: 1= 2pt; background: white;}=0D* {color: black;}=0D=0D#slide0 h1 {font-size: = 200%; border: none; margin: 0.5em 0 0.25em;}=0D#slide0 h3 {margin: 0; pad= ding: 0;}=0D#slide0 h4 {margin: 0 0 0.5em; padding: 0;}=0D#slide0 {margin= -bottom: 3em;}=0D=0Dh1 {border-top: 2pt solid gray; border-bottom: 1px do= tted silver;}=0D.extra {background: transparent !important;}=0Ddiv.extra,= pre.extra, .example {font-size: 10pt; color: #333;}=0Dul.extra a {font-w= eight: bold;}=0Dp.example {display: none;}=0D=0D#header {display: none;}=0D= #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style:= italic;}=0D#footer h2, #controls {display: none;}=0D=0D#currentSlide {di= splay: none;} \ No newline at end of file Added: trunk/SQLObject/docs/presentation-2004-11/ui/s5-core.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/s5-core.css 2004-11-11 1= 4:12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/s5-core.css 2004-11-11 1= 4:33:25 UTC (rev 349) @@ -0,0 +1,9 @@ +/* Do not edit or override these styles! The system will likely break if= you do. */ + +div#header, div#footer, div.slide {position: absolute;} +html>body div#header, html>body div#footer, html>body div.slide {positio= n: fixed;} +div.slide { visibility: hidden;} +#slide0 {visibility: visible;} +div#controls {position: absolute;} +#footer>div#controls {position: fixed;} +.handout {display: none;} Added: trunk/SQLObject/docs/presentation-2004-11/ui/slides.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/slides.css 2004-11-11 14= :12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/slides.css 2004-11-11 14= :33:25 UTC (rev 349) @@ -0,0 +1,3 @@ +@import url(s5-core.css); /* required to make the slide show run at all = */ +@import url(framing.css); /* sets basic placement and size of slide comp= onents */ +@import url(pretty.css); /* stuff that makes the slides look better tha= n blah */ Added: trunk/SQLObject/docs/presentation-2004-11/ui/slides.js =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/SQLObject/docs/presentation-2004-11/ui/slides.js 2004-11-11 14:= 12:55 UTC (rev 348) +++ trunk/SQLObject/docs/presentation-2004-11/ui/slides.js 2004-11-11 14:= 33:25 UTC (rev 349) @@ -0,0 +1,256 @@ +// S5 slides.js -- released under CC by-sa 2.0 license +// +// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for inf= ormation=20 +// about all the wonderful and talented contributors to this code! + +var snum =3D 0; +var smax =3D 1; +var undef; +var slcss =3D 1; +var isIE =3D navigator.appName =3D=3D 'Microsoft Internet Explorer' ? 1 = : 0; +var isOp =3D navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; +var isGe =3D navigator.userAgent.indexOf('Gecko') > -1 && navigator.user= Agent.indexOf('Safari') < 1 ? 1 : 0; +var slideCSS =3D document.getElementById('slideProj').href; + +function isClass(object, className) { + return (object.className.search('(^|\\s)' + className + '(\\s|$)') !=3D= -1); +} + +function GetElementsWithClassName(elementName,className) { + var allElements =3D document.getElementsByTagName(elementName); + var elemColl =3D new Array(); + for (i =3D 0; i< allElements.length; i++) { + if (isClass(allElements[i], className)) { + elemColl[elemColl.length] =3D allElements[i]; + } + } + return elemColl; +} + +function isParentOrSelf(element, id) { + if (element =3D=3D null || element.nodeName=3D=3D'BODY') return false; + else if (element.id =3D=3D id) return true; + else return isParentOrSelf(element.parentNode, id); +} + +function nodeValue(node) { + var result =3D ""; + if (node.nodeType =3D=3D 1) { + var children =3D node.childNodes; + for ( i =3D 0; i < children.length; ++i ) { + result +=3D nodeValue(children[i]); + } =09 + } + else if (node.nodeType =3D=3D 3) { + result =3D node.nodeValue; + } + return(result); +} + +function slideLabel() { + var slideColl =3D GetElementsWithClassName('div','slide'); + var list =3D document.getElementById('jumplist'); + smax =3D slideColl.length; + for (n =3D 0; n < smax; n++) { + var obj =3D slideColl[n]; + + var did =3D 'slide' + n.toString(); + obj.setAttribute('id',did); + if(isOp) continue; + + var otext =3D ''; + var menu =3D obj.firstChild; + if (!menu) continue; // to cope with empty slides + while (menu && menu.nodeType =3D=3D 3) { + menu =3D menu.nextSibling; + } + if (!menu) continue; // to cope with slides with only text nodes + + var menunodes =3D menu.childNodes; + for (o =3D 0; o < menunodes.length; o++) { + otext +=3D nodeValue(menunodes[o]); + } + list.options[list.length] =3D new Option(n+' : ' +otext,n); + } +} + +function currentSlide() { + var cs; + if (document.getElementById) { + cs =3D document.getElementById('currentSlide'); + } else { + cs =3D document.currentSlide; + } + cs.innerHTML =3D '<span id=3D"csHere">' + snum + '<\/span> ' +=20 + '<span id=3D"csSep">\/<\/span> ' +=20 + '<span id=3D"csTotal">' + (smax-1) + '<\/span>'; + if (snum =3D=3D 0) { + cs.style.visibility =3D 'hidden'; + } else { + cs.style.visibility =3D 'visible'; + } +} + +function go(inc) { + if (document.getElementById("slideProj").disabled) return; + var cid =3D 'slide' + snum; + if (inc !=3D 'j') { + snum +=3D inc; + lmax =3D smax - 1; + if (snum > lmax) snum =3D 0; + if (snum < 0) snum =3D lmax; + } else { + snum =3D parseInt(document.getElementById('jumplist').value); + } + var nid =3D 'slide' + snum; + var ne =3D document.getElementById(nid); + if (!ne) { + ne =3D document.getElementById('slide0'); + snum =3D 0; + } + document.getElementById(cid).style.visibility =3D 'hidden'; + ne.style.visibility =3D 'visible'; + document.getElementById('jumplist').selectedIndex =3D snum; + currentSlide(); +} + +function toggle() { + var slideColl =3D GetElementsWithClassName('div','slide'); + var obj =3D document.getElementById('slideProj'); + if (!obj.disabled) { + obj.disabled =3D true; + for (n =3D 0; n < smax; n++) { + var slide =3D slideColl[n]; + slide.style.visibility =3D 'visible'; + } + } else { + obj.disabled =3D false; + for (n =3D 0; n < smax; n++) { + var slide =3D slideColl[n]; + slide.style.visibility =3D 'hidden'; + } + slideColl[snum].style.visibility =3D 'visible'; + } +} + +function showHide(action) { + var obj =3D document.getElementById('jumplist'); + switch (action) { + case 's': obj.style.visibility =3D 'visible'; break; + case 'h': obj.style.visibility =3D 'hidden'; break; + case 'k': + if (obj.style.visibility !=3D 'visible') { + obj.style.visibility =3D 'visible'; + } else { + obj.style.visibility =3D 'hidden'; + } + break; + } +} + +// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/) +function keys(key) { + if (!key) { + key =3D event; + key.which =3D key.keyCode; + } + switch (key.which) { + case 10: // return + case 13: // enter + if (window.event && isParentOrSelf(window.event.srcElement, "controls= ")) return; + if (key.target && isParentOrSelf(key.target, "controls")) return; + case 32: // spacebar + case 34: // page down + case 39: // rightkey + case 40: // downkey + go(1); + break; + case 33: // page up + case 37: // leftkey + case 38: // upkey + go(-1); + break; + case 84: // t + toggle(); + break; + case 67: // c + showHide('k'); + break; + } +} + +function clicker(e) { + var target; + if (window.event) { + target =3D window.event.srcElement; + e =3D window.event; + } else target =3D e.target; + if (target.href !=3D null || isParentOrSelf(target, 'controls')) retur= n true; + if (!e.which || e.which =3D=3D 1) go(1); +} + +function slideJump() { + if (window.location.hash =3D=3D null) return; + var sregex =3D /^#slide(\d+)$/; + var matches =3D sregex.exec(window.location.hash); + var dest =3D null; + if (matches !=3D null) { + dest =3D parseInt(matches[1]); + } else { + var target =3D window.location.hash.slice(1); + var targetElement =3D null; + var aelements =3D document.getElementsByTagName("a"); + for (i =3D 0; i < aelements.length; i++) { + var aelement =3D aelements[i]; + if ( (aelement.name && aelement.name =3D=3D target) + || (aelement.id && aelement.id =3D=3D target) ) { + targetElement =3D aelement; + break; + } + } + while(targetElement !=3D null && targetElement.nodeName !=3D "body") { + if (targetElement.className =3D=3D "slide") break; + targetElement =3D targetElement.parentNode; + } + if (targetElement !=3D null && targetElement.className =3D=3D "slide")= { + dest =3D parseInt(targetElement.id.slice(1)); + } + } + if (dest !=3D null) + go(dest - snum); + } +=20 +function createControls() { + controlsDiv =3D document.getElementById("controls"); + if (!controlsDiv) return; + controlsDiv.innerHTML =3D '<form action=3D"#" id=3D"controlForm">' + + '<div>' + + '<a accesskey=3D"t" id=3D"toggle" href=3D"javascript:toggle();">Ø<= \/a>' + + '<a accesskey=3D"z" id=3D"prev" href=3D"javascript:go(-1);">«<\/a= >' + + '<a accesskey=3D"x" id=3D"next" href=3D"javascript:go(1);">»<\/a>= ' + + '<\/div>' + + '<div onmouseover=3D"showHide(\'s\');" onmouseout=3D"showHide(\'h\');">= <select id=3D"jumplist" onchange=3D"go(\'j\');"><\/select><\/div>' + + '<\/form>'; +} + +function notOperaFix() { + var obj =3D document.getElementById('slideProj'); + obj.setAttribute('media','screen'); + if (isGe) { + obj.setAttribute('href','null'); // Gecko fix + obj.setAttribute('href',slideCSS); // Gecko fix + } +} + +function startup() { + if (!isOp) createControls(); + slideLabel(); + if (!isOp) { =09 + notOperaFix(); + slideJump(); + document.onkeyup =3D keys; + document.onclick =3D clicker; + } +} + +window.onload =3D startup; |