On Oct 30, 2007, at 1:35 PM, Ron wrote:

>
> I guess I should explain further what I'm trying to build.  My app is
> a tool to help with managing clusters.  This includes everything from
> Datacenters, Racks, Servers, Switches, etc.  I don't know ahead of
> time the sorts of specific Things and functionality that might be
> useful so I'm trying to make things as flexible, generic, and easy to
> extend as possible.  So at the core I suppose you could call this
> Thing/Attributes abstraction the framework upon which I and others
> would code "drivers" like Server, SunServer, AppleServer, Switch,
> CiscoSwitch, CiscoRouter, Pool, Location, etc etc.  All those together
> with a command line interface to facilitate scripting is an app called
> clusto.  So, I'm a sysadmin and I'm using this tool.  I just bought a
> Load Balancer 5000.  I immediately put it into my system as a plain
> old LoadBalancer(manufacturer='Load Balancer', model='5000').  Later
> on I decide that I'd like clusto to be able to add servers to my fancy
> LoadBalancer5000 configuration.  Nobody else has implemented the
> functionality yet, so in true open source form, I dive in and do it
> myself:
>
> class LoadBalancer5000(LoadBalancer):
>   meta_attrs = [('manufacturer',  'Load Balancer'), ('model', '5000')]
>
>   def addServer(self, someserver):
>      # magic
>
> done.  No futzing with the database, no diving into obscure parts of
> the code, nothing.  I just plop that class into the right path and it
> works.  With a clever command line and scripting interface it may even
> be useful.

If i were writing an app like that, id actualy have some kind of end- 
user commands:  "create new type -> LoadBalancer5000;  convert all  
"LoadBalancer" + "model=5000" to "LoadBalancer5000".  i.e. i *would*  
update the data, but id make it easy.  because the database is much  
more efficient if you use a single horizontal column to differentiate  
types.  if you have to dive into vertical attributes every time, that  
greatly limits functionality.  what if i wanted to get a report of  
25,000 objects and their types really quickly ?  would you rather  
iterate through 25000 rows, or 25000 * total number of attributes,  
apply complex rules on the client side to aggrgate the attribute rows  
together and determine types, etc ?  you're not really making the  
best usage of the database in that case.

this is actually not a unique scenario at all.  If you work with  
search engines, often you have to configure a combination of  
"horizontal" and "vertical" properties for documents which are  
stored.  the "horizontal" properties are those that can be searched  
very quickly, whereas the "vertical" are those which require  
secondary queries to retrieve (like the document's full list of  
metatags).

>> theres no straightforward way for me to
>> get a list of all the AppleServers, for example, since id have to
>> query all these different attributes just to identify those objects.
>>
>
> So, underneath the hood, to get all the AppleServers you'd do:
>
> ## pseudocode
> for attr in SomeThingClass.all_meta_attrs:
>  # all_meta_attrs is a list of all the meta_attrs for that class going
> up the inheritance chain, cls.mro()
>  thingquery += and_(Attribute.c.key==attr[0],
> Attribute.c.value==attr[1])
>
> select(and_(Thing.c.name==Attribute.c.name, thingquery))
> #that should get all the Thing that can be managed by the given
> class.  Maybe not "straightforward" but not terribly complex either.
>
> So, in my implementation, the metaclass mapped each Class to such a
> select.  I am mapping against different selectables, and so having
> different mappers made sense.  So if I did SA functions like:
>
> AppleServer.select(and_(Attribute.c.key='numports',
> Attribute.c.value='2'))
>
> I'd only get AppleServers with ('numports', '2') and not any other
> types of Things.  At one point I got things working as I just
> described, but I'm not sure if that was the case in my latest
> iteration of the code.

you can still have a bunch of selects that you just feed into a Thing  
query.  its not critical to have them "mapped".

>
>> however, didnt you say that your class
>> attributes come from a different table ?  in that case this is still
>> not going to work...if youre relying upon eager loading of related ,
>> multiple sets of rows, thats not available until well after the
>> polymorphic decisions have been made.  the most that polymorhpic_func
>> could get is the first row with the Thing's primary key in it.
>>
>
> That's a good point.  I suppose the function could use that primary
> key to select stuff out of the Attributes table and then analyze those
> to determine the proper class.  But that seems like an unhappy hack.
> Why isn't there a hook into a post-populate part of the mapping?  Or
> whatever the absolute very last step of making an instance happens to
> be.  Does such a thing exist and I just missed it?

no, we'd have to add a hook there too.  every hook slows down  
sqlalchemy's load time just a little bit more, not because of the  
hook itself but because SA has to check for the presence of one in  
all cases.  i have modified the "hook" system in trunk to just a  
quick "hookname in somedictionary" check so its not terrible but i  
still try to avoid adding new ones.


> One thing I lose by doing it this is having Server mapped to only its
> subset of Things in the db.  I was using assign_mapper to accomplish
> two different goals.  One, to populate instances of Things with their
> attribute and row values.  Two, to add useful member functions
> like .select() to the class so that I could more cleanly work on the
> subset managed by the class.  I suppose I could write my own functions
> to provide the latter and that might actually be the more correct way
> to expose such functionality.
>


yes mappers are only for describing how a class is persisted in the  
database.  while there are class behaviors that then generate from  
that persistence description, its not the place to add new class  
behaviors that are not directly linked to a persistence mapping.   
obviously its a fuzzy line.



--~--~---------~--~----~------------~-------~--~----~
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