Gary, Thanks for the reply.
> On Feb 13, 2006, at 10:33 PM, Shaun Cutts wrote: > > > Um... > > > > I guess I must have asked too many questions at once :) > > :-) and this is still a bit much for me. > > > I've implemented > > a first pass of a container for external data and got it working on > > some > > of my collections. > > > > I've included the (first pass of the) base DBContainer and DBContained > > objects for criticism, and would be very grateful if anyone would like > > to take a crack at it. > > It looks like an interesting approach--more low-level than I would > have expected for a first cut, and *maybe* more low-level than > necessary. I wish I had more time to look at it. If there were anything more higher-level, I would be happy.... I will eventually be needing "paged" collections to, though, so I can't give up too much control. > > > Keep in mind, this is my first time working with the system, so I'm > > sure > > I'm going about some things the wrong way. In particular, I already > > think: > > > > 1) Instead of have the contained object update the container, I should > > rely on the event notification system. > > Events are a tool for disconnected notification. calling a method on > an object is sending a message directly to the interested party. Not > everything should be an event. If a communication between two > components is a core aspect of your design, maybe direct method calls > are more appropriate. The problem now is that the default edit view uses __setitem__ for the contained object, so I get one db update per column, whereas (I hope!) the event is fired after all the column updates are complete. Not a problem for the prototype, but maybe annoying in production system when Postgres is busier with other users as well. Of course, I may be overriding the default edit view anyway.... So the problem isn't the coupling between DBContained and DBContainer per se. Its sort of like I want the editView to enforce a transaction protocol, and want to use the Event as a proxy for "commit". Note: I don't think I want dirty object in the system; otherwise I could use a lazy protocol where the container just checks -- say at demarshalling time (but probably on shutdown at least, if we are interrupted?) -- whether it has any updates to write. If I did want to go to a lazy protocol, is there a way to register things for getting triggered on shutdown. > > > 2) Right now, the system works by translating objects "at the border" > > (in IExternalContainer). Some translation is necessary, for > > instance, to > > move from mx.DateTime to datetime.datetime, but still I think I should > > somehow be making use of the "adaptor" interface. > > If there's not an object to adapt then you have to start somewhere. > My glance at the code seemed to show that you were making a > reasonable choice. Another approach might be to have an abstract > "row" object that could represent any columns (a dict or something), > and named adapters registered for the row interface plus the name of > the generating table. I dunno, do what your app needs and refine it > as you discover what works. > I actually do have a row object from my database code... but (as I learned) it is a bit of a pain to use directly, since: 1) datatypes are somewhat non-standard (dates, particularly), and 2) it is a bit messy to use with annotations because Row uses __getattribute__, though this is probably a design flaw in the Row class hierarchy. My thought was that I might want to be adapting my row objects (or their interfaces to be precise). Indeed, I am, but in a nonstandard way, as "IExternalDatabase"-derivatives do the translation. My plan now is: have the DBContained base class be a "protoadapter" that does all the column datatype translations and validation; its subclasses will adapt specific Row-derived classes, which have concrete sets of columns. I guess there is no particular machinery to use to present this pattern: one hierarchy adapts another hierarchy? > > 3) Along these same lines, IDBContainer._containedType should > > really be > > an interface (Object( schema = IDBContained )) > > > > Note: is there a tutorial on writing containers anywhere I should have > > read? I mainly figured this out by banging on it and fishing around in > > the code. I'd love to figure out, for instance, what is really > > happening > > with the traversals (with some interaction diagrams). I do think it > > was > > harder than it should have been. (But, then again, I think that about > > most things...:)) > > Don't know of a tutorial. Sounds like you are interested in > traversal, though, which is different. Look at zope.app.traversing, > or zope.app.container.traversal. The headline is that there are two > kinds of traversal: URL path traversal and TALES path traversal. > They have different adapters. When debugging, I had a lot of problems understanding what was happening because I didn't understand how traversal was trying to get data... It would just be nice to have more design doc -- especially interaction diagrams -- to refer to for some of the more complex parts of the system. (Stephan's book's diagrams for events are useful.) > > > BTW in my humble opinion, ILocation.__name__ is not well named. When I > > first got an error referring to __name__ I thought it was expecting a > > class object. And what happens when, for some strange reason, someone > > wants to put a class in a container, and doesn't like its default > > name? > > Not sure if that's a real use case for an ILocation. > > That said, it's a reasonable POV to say that Zope shouldn't claim > __*__ names. But we do, so, well, yeah, we do. ;-) > > Gary I would prefer that zope names have some unique prefix... maybe : __zope_name__. This would also help greping/googling. ("__name__" is a particularly conflict prone case.) Thanks, - Shaun _______________________________________________ Zope3-users mailing list Zope3email@example.com http://mail.zope.org/mailman/listinfo/zope3-users