Oleg Broytmann wrote:
> On Wed, Oct 18, 2006 at 05:38:53PM -0300, Johan Dahlin wrote:
>> Any hints on how to solve this?
> 
>    I need to look into it. You know, the code is tricky...

Okay, I found out what needed to be done.

selectBy does not use the .q magic so we need to build up the query
manually. It turned out to be not so easy:

SQLObject.selectBy uses DBAPI._SO_columnClause which cannot handle
inheritence, it was not designed with that in mind.
I had to copy over parts of _SO_columnClause into InheritedSQLObject and
build up a query which does a join on the parent classes.

Tested using postgres and sqlite.

Johan

Index: inheritance/tests/test_inherited_foreignKey.py
===================================================================
--- inheritance/tests/test_inherited_foreignKey.py      (revisão 5149)
+++ inheritance/tests/test_inherited_foreignKey.py      (cópia de trabalho)
@@ -11,12 +11,17 @@
     lastName = StringCol()
     note = ForeignKey("Note", default=None)
 
+class Paper(SQLObject):
+    content = StringCol()
+
 class EmployeeWithNotes(PersonWithNotes):
-    _inheritable = False
+    #_inheritable = False
+    paper = ForeignKey("Paper", default=None)
 
 def setup():
     setupClass(Note)
     setupClass(PersonWithNotes)
+    setupClass(Paper)
     setupClass(EmployeeWithNotes)
 
     note = Note(text="person")
@@ -24,6 +29,9 @@
     note = Note(text="employee")
     EmployeeWithNotes(firstName='Project', lastName='Leader', note=note)
 
+    paper = Paper(content="secret")
+    EmployeeWithNotes(firstName='Senior', lastName='Clerk', paper=paper)
+    PersonWithNotes(firstName='Some', lastName='Person')
 
 def test_inheritance():
     setup()
@@ -35,3 +42,31 @@
     employee = EmployeeWithNotes.get(2)
     assert isinstance(employee, EmployeeWithNotes)
     assert employee.note.text == "employee"
+
+    persons = PersonWithNotes.select(PersonWithNotes.q.noteID <> None)
+    assert persons.count() == 2
+
+    persons = PersonWithNotes.selectBy(noteID=person.note.id)
+    assert persons.count() == 1
+
+    persons = EmployeeWithNotes.select(PersonWithNotes.q.noteID <> None)
+    assert persons.count() == 1
+
+    persons = PersonWithNotes.selectBy(noteID=person.note.id)
+    assert persons.count() == 1
+
+    persons = PersonWithNotes.selectBy(note=person.note)
+    assert persons.count() == 1
+
+    persons = PersonWithNotes.selectBy(note=None)
+    assert persons.count() == 2
+
+    persons = EmployeeWithNotes.selectBy(paper=None)
+    assert persons.count() == 1
+
+    persons = EmployeeWithNotes.selectBy(note=employee.note,
+                                         paper=employee.paper)
+    assert persons.count() == 1
+
+    persons = EmployeeWithNotes.selectBy()
+    assert persons.count() == 2
Index: inheritance/__init__.py
===================================================================
--- inheritance/__init__.py     (revisão 5150)
+++ inheritance/__init__.py     (cópia de trabalho)
@@ -1,6 +1,6 @@
 from sqlobject import sqlbuilder
 from sqlobject import classregistry
-from sqlobject.col import StringCol, ForeignKey
+from sqlobject.col import StringCol, ForeignKey, popKey
 from sqlobject.main import sqlmeta, SQLObject, SelectResults, True, False, \
    makeProperties, getterName, setterName
 import iteration
@@ -383,14 +384,60 @@
                 clause, *args, **kwargs)
     select = classmethod(select)
 
+    def _SO_prepareSelectBy(cls, conn, kw):
+        ops = {None: "IS"}
+        data = {}
+        clauses = []
+        tables = []
+
+        # Inherited attributes
+        currentClass = cls.sqlmeta.parentClass
+        while currentClass:
+            tableName = currentClass.sqlmeta.table
+            for c in currentClass.sqlmeta.columns.values():
+                name = c.name
+                if name == 'childName':
+                    continue
+                if not tableName in tables:
+                    tables.append(currentClass)
+                dbName = tableName + '.' + c.dbName
+                if name in kw:
+                    data[dbName] = popKey(kw, name)
+                elif c.foreignName in kw:
+                    obj = popKey(kw, c.foreignName)
+                    if isinstance(obj, SQLObject):
+                        data[dbName] = obj.id
+                    else:
+                        data[dbName] = obj
+            currentClass = currentClass.sqlmeta.parentClass
+
+        clauses.extend(['%s %s %s' %
+                        (dbName, ops.get(value, "="), conn.sqlrepr(value))
+                        for dbName, value in data.items()])
+
+        # join in parent tables
+        for table in tables:
+            for c in [table.q.childName == cls.sqlmeta.childName,
+                      table.q.id == cls.q.id]:
+                clauses.append(conn.sqlrepr(c))
+
+        # columns in the same class, reuse _SO_columnClause
+        normal = conn._SO_columnClause(cls, kw)
+        if normal:
+            clauses.extend(normal.split(' AND '))
+
+        table_names = [table.sqlmeta.table for table in tables]
+        clause = ' AND '.join(clauses)
+        return clause, table_names
+    _SO_prepareSelectBy = classmethod(_SO_prepareSelectBy)
+
     def selectBy(cls, connection=None, **kw):
-        clause = []
-        for name, value in kw.items():
-            clause.append(getattr(cls.q, name) == value)
-        clause = reduce(sqlbuilder.AND, clause)
         conn = connection or cls._connection
-        return cls.SelectResultsClass(cls, clause, connection=conn)
-
+        clause, table_names = cls._SO_prepareSelectBy(conn, kw)
+        return cls.SelectResultsClass(cls,
+                                      clauseTables=table_names,
+                                      clause=clause,
+                                      connection=conn)
     selectBy = classmethod(selectBy)
 
     def destroySelf(self):
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
sqlobject-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sqlobject-discuss

Reply via email to