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