Hey Mikkel, thanks you for your works, it is working fine for me. Feel free to merge this branch into lp:zeitgeist once you thought about my three comments ;) Markus > === modified file '_zeitgeist/engine/main.py' > --- _zeitgeist/engine/main.py   2010-05-03 16:32:00 +0000 > +++ _zeitgeist/engine/main.py   2010-05-12 19:32:33 +0000 > @@ -32,7 +32,7 @@ >  from collections import defaultdict > >  from zeitgeist.datamodel import Event as OrigEvent, StorageState, TimeRange, \ > -       ResultType, get_timestamp_for_now, Interpretation > +       ResultType, get_timestamp_for_now, Interpretation, Symbol >  from _zeitgeist.engine.datamodel import Event, Subject >  from _zeitgeist.engine.extension import ExtensionsCollection, load_class >  from _zeitgeist.engine import constants > @@ -163,16 +163,51 @@ >                for (event_template, subject_template) in self._build_templates(templates): >                        subwhere = WhereClause(WhereClause.AND) >                        try: > -                               for key in ("interpretation", "manifestation", "actor"): > -                                       value = getattr(event_template, key) > -                                       if value: > -                                               subwhere.add("%s = ?" % key, > -                                                       getattr(self, "_" + key).id(value)) > -                               for key in ("interpretation", "manifestation", "mimetype"): > -                                       value = getattr(subject_template, key) > -                                       if value: > -                                               subwhere.add("subj_%s = ?" % key, > -                                                       getattr(self, "_" + key).id(value)) > +                               # Expand event interpretation children > +                               event_interp_where = WhereClause(WhereClause.OR) > +                               for child_interp in > (Symbol.find_child_uris_extended(event_template.interpretation)): > +                                       if child_interp: > +                                               event_interp_where.add("interpretation = ?", > +                                                                      self._interpretation.id(child_interp)) > +                               if event_interp_where: > +                                       subwhere.extend(event_interp_where) > + > +                               # Expand event manifestation children > +                               event_manif_where = WhereClause(WhereClause.OR) > +                               for child_manif in > (Symbol.find_child_uris_extended(event_template.manifestation)): > +                                       if child_manif: > +                                               event_manif_where.add("manifestation = ?", > +                                                                     self._manifestation.id(child_manif)) > +                               if event_manif_where: > +                                       subwhere.extend(event_manif_where) > + > +                               # Expand subject interpretation children > +                               su_interp_where = WhereClause(WhereClause.OR) > +                               for child_interp in > (Symbol.find_child_uris_extended(subject_template.interpretation)): > +                                       if child_interp: > +                                               su_interp_where.add("subj_interpretation = ?", > +                                                                   self._interpretation.id(child_interp)) > +                               if su_interp_where: > +                                       subwhere.extend(su_interp_where) > + > +                               # Expand subject manifestation children > +                               su_manif_where = WhereClause(WhereClause.OR) > +                               for child_manif in > (Symbol.find_child_uris_extended(subject_template.manifestation)): > +                                       if child_manif: > +                                               su_manif_where.add("subj_manifestation = ?", > +                                                                  self._manifestation.id(child_manif)) > +                               if su_manif_where: > +                                       subwhere.extend(su_manif_where) > + > +                               # FIXME: Expand mime children as well. > +                               # Right now we only do exact matching for mimetypes > +                               if subject_template.mimetype: > +                                       subwhere.add("subj_mimetype = ?", > +                                                    self._mimetype.id(subject_tempalte.mimetype)) > + > +                               if event_template.actor: > +                                       subwhere.add("actor = ?", > +                                                    self._actor.id(event_template.actor)) >                        except KeyError: >                                # Value not in DB >                                where_or.register_no_result() > @@ -183,6 +218,7 @@ >                                        subwhere.add("subj_%s = ?" % key, value) >                        where_or.extend(subwhere) > > +               print "SQL:  ", where_or.sql, where_or.arguments Do you still need this output, if so, I think this should be converted into logging.debug() >                return where_or > >        def _build_sql_event_filter(self, time_range, templates, storage_state): > > === modified file 'test/datamodel-test.py' > --- test/datamodel-test.py      2010-04-28 19:14:21 +0000 > +++ test/datamodel-test.py      2010-05-12 19:32:33 +0000 > @@ -51,6 +51,47 @@ >                self.assertTrue(f.display_name != None) >                self.assertTrue(f.doc != None) > > +class RelationshipTest (unittest.TestCase): > +       """ > +       Tests for parent/child relationships in the loaded ontologies > +       """ > + > +       def testDirectParents (self): > +               """ > +               Tests relationship tracking for immediate parents > +               """ > +               self.assertTrue(Interpretation.AUDIO.is_a(Interpretation.MEDIA)) > + > +       def testSecondLevelParents (self): > +               """ > +               Tests relationship tracking for second level parents > +               """ > +               self.assertTrue(Interpretation.VECTOR_IMAGE.is_a(Interpretation.MEDIA)) > +               self.assertTrue(Interpretation.VECTOR_IMAGE.is_a(Interpretation.IMAGE)) > + > +       def testRootParents (self): > +               """ > +               Tests relationship tracking for root nodes, ie Interpretation > +               and Manifestation > +               """ > +               self.assertTrue(Interpretation.VECTOR_IMAGE.is_a(Interpretation)) > +               self.assertTrue(Manifestation.FILE_DATA_OBJECT.is_a(Manifestation)) > +               self.assertTrue(Manifestation.USER_ACTIVITY.is_a(Manifestation)) > + > +       def testReflecsive (self): > +               """ > +               Assert that a symbol is a child of itself > +               """ > +               self.assertTrue(Manifestation.USER_ACTIVITY.is_a(Manifestation.USER_ACTIVITY)) > + > +       def testFindExtendedChildren (self): > +               self.assertEquals(["foo://bar"], > Symbol.find_child_uris_extended("foo://bar")) > +               self.assertEquals(["http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Icon", > + > "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#VectorImage", > + > "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Cursor", > + > "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#RasterImage", > + > "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Image"], > + > Symbol.find_child_uris_extended("http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Image")) > >  class EventTest (unittest.TestCase): >        def setUp(self): > @@ -116,6 +157,17 @@ >                e.manifestation="ILLEGAL SNAFU" >                self.assertFalse(e.matches_template(template)) > > +       def testTemplateParentMatching(self): > +               template = Event.new_for_values( > +                                       manifestation=Manifestation.EVENT_MANIFESTATION, > +                                       subject_interpretation=Interpretation) > + > +               e = Event.new_for_values( > +                                       manifestation=Manifestation.USER_ACTIVITY, > +                                       subject_interpretation=Interpretation.TEXT_DOCUMENT, > +                                       subject_text="Foo") > +               self.assertTrue(e.matches_template(template)) > + >        def testTemplateFiltering(self): >                template = Event.new_for_values(interpretation="stfu:OpenEvent") >                events = parse_events("test/data/five_events.js") > > === added file 'test/test-sql.py' > --- test/test-sql.py    1970-01-01 00:00:00 +0000 > +++ test/test-sql.py    2010-05-12 19:32:33 +0000 > @@ -0,0 +1,51 @@ > +#! /usr/bin/python > +# -.- coding: utf-8 -.- > + > +# Zeitgeist > +# > +# Copyright © 2010 Mikkel Kamstrup Erlandsen