What I don't like about my own solution, after all (see my 3rd post on
this thread, after the accidental 2nd one prematurely submitted), is
that it recursively traverses the Itemtype graph to make a list of
itemtypes to constrain the scope of a request for the list of features
upon which a given feature is dependent.  That traversal makes it
pretty slow, and moreover it represents "other" activity outside of
the query itself.

Intuitively I feel that there ought to be some query syntax that
expresses the same request that I am trying to make entirely in sql,
without this pre-traversal step to build an "in_() list" of Itemtype
nodes.  On the other hand, I have seen Mike write that if sqlalchemy
were expected to traverse arbitrary m:m structures to arbitrary depth
in creating joins to satisfy a query, things could get out of hand too
quickly.  The standard problem of having too many possibilities in the
space of characterizing the desired solutions, and those possibilities
increasing faster than the means of describing them, leaving too much
ambiguity to be worth attempting to support a general solution.

So maybe my current solution with this recursively built "in_()
list" (of itemtypes that are the root_itemtype of features, following
the itemtype inheritance graph 'upward' from a given starting feature)
is about as good as it gets.  I'm just reaching out intuitively to see
if anyone says something that sparks a leap forward in my
understanding of the shape of this type of problem.

Will now respond to Svilen's post.

Eric


On Nov 25, 2:04 am, Eric Ongerth <[EMAIL PROTECTED]> wrote:
> Arghh.  Accidentally hitting 'Tab' in google groups takes you to the
> 'Send' button, then your next spacebar press prematurely sends your
> post.
>
> Ok, add the following property on Itemtype:
>
> @property
> def full_heritage(self):
>     result = self.inherits[:]
>     if result:
>         for inherited in self.inherits:
>             result.extend(inherited.full_heritage)
>     return result
>
> ... this is just recursively building a list of all nodes involved in
> inheritance from a given Itemtype node upward through the graph.
>
> Then change the method on Feature:
>
> def determinants_in_scope_of(self, itemtype):
>     targets = map(lambda x: x.name, itemtype.full_heritage)
>     targets.append(itemtype.name)
>     return (session.query(Feature)
>         .join(FeatureDependency.determinant)
>         .join(Feature.root_itemtype)
>         .filter(and_(FeatureDependency.dependent_id==self.id,
>             Itemtype.name.in_(targets)))).all()
>
> Now this machinery does exactly what I want.  I look forward to
> showing you what it's really used for eventually.  Ciao!
>
> Eric
>
> On Nov 25, 1:57 am, Eric Ongerth <[EMAIL PROTECTED]> wrote:
>
> > Well!  I guess that's exactly why we post sometimes -- the process of
> > producing the test case bumps the unconscious forward a few steps.  I
> > quit and did some pleasure reading for a while then came back.  Here's
> > my own answer that does exactly what I needed it to do.
>
> > Add the following property on Itemtype:
>
> > @property
> > def full_heritage(self):
>
> > On Nov 25, 12:42 am, Eric Ongerth <[EMAIL PROTECTED]> wrote:
>
> > > Unfortunately, I posted the wrong version of my Itemtype class above;
> > > fortunately it wasn't important for what I was trying to show.  Please
> > > replace class Itemtype with the following, and note the additional
> > > test lines and commentary which I also forgot to include.
>
> > > class Itemtype(object):
>
> > >     def __repr__(self):
> > >         return 'Itemtype: %s' % (self.name)
>
> > >     @property
> > >     def inherited_features(self):
> > >         return ([feature for base_itemtype in self.inherits for
> > > feature in base_itemtype.features])
>
> > >     @property
> > >     def features(self):
> > >         result = self.own_features[:]
> > >         if self.inherits:
> > >             result.extend(self.inherited_features[:])
> > >         return result
>
> > >     @property
> > >     def dependent_features(self):
> > >         return [f for f in self.features if f.determinants]
>
> > >     @property
> > >     def independent_features(self):
> > >         return [f for f in self.features if not f.determinants]
>
> > > The code i posted the first time was not the right code for the
> > > inherited_features and features properties on Itemtype.  I must have
> > > cut and pasted from the wrong test file.
>
> > > Please observe the following interactions which may help paint a
> > > clearer picture of what I'm doing with this stuff.
>
> > > >>>Boot.features
>
> > > [Footwear Gender, Footwear US Shoe Size, Product Manufacturer, Product
> > > Model, Product Year, Product Weight]
>
> > > >>>Boot.dependent_features
>
> > > [Product Weight]
>
> > > >>>Boot.independent_features
>
> > > [Footwear Gender, Footwear US Shoe Size, Product Manufacturer, Product
> > > Model, Product Year]
>
> > > >>>Footwear.inherited_features
>
> > > [Product Manufacturer, Product Model, Product Year, Product Weight]
>
> > > >>>Footwear.own_features
>
> > > [Footwear Gender, Footwear US Shoe Size]
>
> > > These are all examples of some of the useful things I'm using this for
> > > -- keeping track of which variables ('features'), in an inheriting/
> > > cascading type system, are dependent and which ones are independent.
> > > Later, when values are entered and stored for each feature, the
> > > relationships between the values will be constrained by these same
> > > feature dependency links, without having to repeat them at that time.
>
> > > Sorry for the wrong code before.  Oh yeah, I forgot to demonstrate
> > > this too, but it's trivial:
>
> > > >>>Model = session.query(Feature).filter_by(name='Model').one()
> > > >>>Model.dependents
> > > [Product weight]
> > > >>>Gender.dependents
>
> > > [Product weight]
>
> > > ... so all this works the other way around too, though requesting the
> > > dependents of a given feature is not as interesting as requesting a
> > > given feature's determinants.
>
> > > Eric
>
> > > On Nov 24, 11:51 pm, Eric Ongerth <[EMAIL PROTECTED]> wrote:
>
> > > > Below, I have attached a working testcase.  It works, yes -- but my
> > > > question is that I need to make an improved version of a particular
> > > > method on one of my classes.  The following model will probably
> > > > explain itself for the most part.  I'll let you read it first, then
> > > > offer a few explanatory notes afterward just in case.  Finally, at the
> > > > end, I will describe the difference between what the method in
> > > > question does now, and what I would like it to do.
>
> > > > The nature of the response I am seeking is: a description of what I
> > > > need to do to build a better version of the method I'm speaking of,
> > > > including any further insight on the practice of joining at multiple
> > > > levels of a recursive / self-referential (but loop-free) graph.
>
> > > > ---snip---
>
> > > > from sqlalchemy import *
> > > > from sqlalchemy.sql import *
> > > > from sqlalchemy.orm import *
>
> > > > engine = create_engine('sqlite://')
>
> > > > metadata = MetaData(bind=engine)
>
> > > > itemtypes = Table('itemtypes', metadata,
> > > >     Column('name', Text, primary_key=True))
>
> > > > itemtype_inheritance = Table('itemtype_inheritance', metadata,
> > > >     Column('itemtype_name', Text, ForeignKey('itemtypes.name'),
> > > > primary_key=True),
> > > >     Column('parent_name', Text, ForeignKey('itemtypes.name'),
> > > > primary_key=True))
>
> > > > features = Table('features', metadata,
> > > >     Column('id', Integer, primary_key=True),
> > > >     Column('name', Text),
> > > >     Column('root_itemtype_name', Text, ForeignKey('itemtypes.name')))
>
> > > > feature_dependencies = Table('feature_dependencies', metadata,
> > > >     Column('dependent_id', Integer, ForeignKey('features.id'),
> > > > primary_key=True),
> > > >     Column('determinant_id', Integer, ForeignKey('features.id'),
> > > > primary_key=True))
>
> > > > metadata.drop_all()
> > > > metadata.create_all()
>
> > > > itemtypes.insert().execute([
> > > >     {'name': 'Product'},
> > > >     {'name': 'Footwear'},
> > > >     {'name': 'Boot'},
> > > >     {'name': 'Ski'}
> > > > ])
>
> > > > itemtype_inheritance.insert().execute([
> > > >     {'itemtype_name': 'Footwear', 'parent_name': 'Product'},
> > > >     {'itemtype_name': 'Boot', 'parent_name': 'Footwear'},
> > > >     {'itemtype_name': 'Ski', 'parent_name': 'Product'}
> > > > ])
>
> > > > features.insert().execute([
> > > >     {'id': 1, 'name': 'Manufacturer',
> > > > 'root_itemtype_name':'Product' },
> > > >     {'id': 2, 'name': 'Model', 'root_itemtype_name':'Product' },
> > > >     {'id': 3, 'name': 'Year', 'root_itemtype_name':'Product' },
> > > >     {'id': 4, 'name': 'Gender', 'root_itemtype_name':'Footwear' },
> > > >     {'id': 5, 'name': 'US Shoe Size',
> > > > 'root_itemtype_name':'Footwear' },
> > > >     {'id': 6, 'name': 'Length', 'root_itemtype_name':'Ski' },
> > > >     {'id': 7, 'name': 'Weight', 'root_itemtype_name':'Product' }
>
> > > > ])
>
> > > > feature_dependencies.insert().execute([
> > > >     {'dependent_id': 7, 'determinant_id': 1},
> > > >     {'dependent_id': 7, 'determinant_id': 2},
> > > >     {'dependent_id': 7, 'determinant_id': 3},
> > > >     {'dependent_id': 7, 'determinant_id': 4},
> > > >     {'dependent_id': 7, 'determinant_id': 5},
> > > >     {'dependent_id': 7, 'determinant_id': 6}
> > > > ])
>
> > > > class Itemtype(object):
>
> > > >     def __repr__(self):
> > > >         return 'Itemtype: %s' % (self.name)
>
> > > >     @property
> > > >     def inherited_features(self):
> > > >         return reduce(list.extend,
> > > >                       [base_itemtype.features for base_itemtype in
> > > > self.inherits],
> > > >                       [])
>
> > > >     @property
> > > >     def features(self):
> > > >         return self.own_features.extend(self.inherited_features)
>
> > > >     @property
> > > >     def dependent_features(self):
> > > >         return [f for f in self.features if f.determinants]
>
> > > >     @property
> > > >     def independent_features(self):
> > > >         return [f for f in self.features if not f.determinants]
>
> > > > class Feature(object):
>
> > > >     def __repr__(self):
> > > >         return '%s %s' % (self.root_itemtype_name, self.name)
>
> > > >     def determinants_in_scope_of(self, itemtype):
> > > >         return (session.query(Feature)
> > > >                 .join(FeatureDependency.determinant)
> > > >                 .join(Feature.root_itemtype)
> > > >                 .filter(and_(FeatureDependency.dependent_id==self.id,
> > > >                              Itemtype.name==itemtype.name))).all()
>
> > > > class FeatureDependency(object):
>
> > > >     def __repr__(self):
> > > >         return "F_D: %s depends on %s" % (self.dependent.name,
> > > >                                           self.determinant.name)
>
> > > > mapper(Itemtype, itemtypes, properties={
> > > >     'inherits':relation(Itemtype,
> > > >         secondary=itemtype_inheritance,
> > > >         primaryjoin=
> > > > (itemtypes.c.name==itemtype_inheritance.c.itemtype_name),
> > > >         secondaryjoin=
> > > > (itemtype_inheritance.c.parent_name==itemtypes.c.name),
> > > >         backref='progeny'),
> > > >     'own_features':relation(Feature,
> > > >        
>
> ...
>
> read more »
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to