Thread: [SQLObject] thoughts on structure and components
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
From: Bud P. B. <bu...@si...> - 2003-05-08 09:38:21
|
Hi everyone, Been thinking these days and would like to share some of what I came up with. I suppose this could be of interest just for academic purposes or for a possible future refactoring of SQLObject. If it's not of interest, just ignore. My thinking was triggered by: - My wish for higher-level physical types that users construct depending on the application - My difficulties to easily add the things to SQLObject that I expected to be easy: e.g., foreign keys... - I have an intuition (that I cannot materialize) that there is some strong coupling in SqlObject that steepens the learning curve and makes some behavior unintuitive. It may be that also the issues of difficulties of subclassing etc. are falling in this area... As I said, I have no overly clear ideas to offer. So my first product out of this is just a clarification of what concepts (classes) there should be and how they relate with each other. A first rough writeup of my ideas follows here: Concepts: --------- Application Object: An Application Object is independent of backend storage Storable: A superclass that makes application objects storable. It adds methods that interact with the Backend in order to - store - update - delete the object In addition, it provided methods to easily access related objects Backend: An object that manages the interaction with the actual database. It has the following components: - mapping - dbDriver - dbConnection A first version can live with a single driver and connection--a later version may be able to work with multiple databases Connection: An actual connection or connection pool that interacts with the dbms DBdriver: A class that provides functionality that depends on the kind of connection used, typically depending on: - dbms used (e.g., postgres) - DBI module (and version) The DBdriver supports a subset of dbCols Mapping: Description of the physical representation in a dbms-independent way. The mapping is described by the following components: - Attributes of Storable Objects - Relationships of Storable Objects DbCol: A low level physical type to represent a single field in the dbms. It is an abstraction of the actual SQL type since different DBdrivers can map it to different SQL expressions. The types are named closely to standard SQL. Types such as TIMESTAMP could for example be translated to DateTime by a mySQL dbDriver. Attribute: A high-level physical type to represent the higher-level physical rep. This includes marshalling to and from a lower-level representation. Marshalling can do things such as encoding structured objects (phone number with country and area code) to strings, pickling, mapping a single attribute (a point) to multiple columns (x, y or lat,long), etc. /----------------------------------------------------------------- | Bud P. Bruegger, Ph.D. | Sistema (www.sistema.it) | Via U. Bassi, 54 | 58100 Grosseto, Italy | +39-0564-411682 (voice and fax) \----------------------------------------------------------------- |
From: Bud P. B. <bu...@si...> - 2003-05-08 10:13:26
Attachments:
backend-3.png
|
Not sure whether the lists does attachments, but here is a UML class diagram that visualizes my thoughts further --b |
From: Nick <ni...@dd...> - 2003-05-08 14:44:39
|
On Thu, 2003-05-08 at 04:37, Bud P.Bruegger wrote: > Backend: > An object that manages the interaction with the actual database. > It has the following components: > - mapping > - dbDriver > - dbConnection Don't forget cache somewhere, which probably makes more sense to put here than in the Connection. > Mapping: > Description of the physical representation in a dbms-independent way. Isn't mapping dependent on the way the data is stored in the database? Maybe I'm misunderstanding what you mean by mapping. > Attribute: > A high-level physical type to represent the higher-level physical rep. This > includes marshalling to and from a lower-level representation. Marshalling > can do things such as encoding structured objects (phone number with country > and area code) to strings, pickling, mapping a single attribute (a point) to > multiple columns (x, y or lat,long), etc. How does this relate to mapping? It sounds similar. Nick |
From: Bud P. B. <bu...@si...> - 2003-05-08 15:24:31
|
On 08 May 2003 09:44:21 -0500 Nick <ni...@dd...> wrote: > On Thu, 2003-05-08 at 04:37, Bud P.Bruegger wrote: > > Backend: > > An object that manages the interaction with the actual database. > > It has the following components: > > - mapping > > - dbDriver > > - dbConnection > > Don't forget cache somewhere, which probably makes more sense to put > here than in the Connection. Absolutely right! > > Mapping: > > Description of the physical representation in a dbms-independent way. > > Isn't mapping dependent on the way the data is stored in the database? > Maybe I'm misunderstanding what you mean by mapping. Yes, the mapping describes how objects are stored in the dbms but abstracts from the details that differ with the actually used dbms (mysql, postgres, etc). > > Attribute: > > A high-level physical type to represent the higher-level physical rep. > > This includes marshalling to and from a lower-level representation. > > Marshalling can do things such as encoding structured objects (phone > > number with country and area code) to strings, pickling, mapping a single > > attribute (a point) to multiple columns (x, y or lat,long), etc. > > How does this relate to mapping? It sounds similar. It's a component, have a look at the UML class diagram that I attached.. Thanks for the feedback --b |
From: Ian B. <ia...@co...> - 2003-05-09 03:13:08
|
Well, some random thoughts (composed bottom-up, if that helps it make sense) On Thu, 2003-05-08 at 04:37, Bud P.Bruegger wrote: > Hi everyone, > > Been thinking these days and would like to share some of what I came > up with. I suppose this could be of interest just for academic > purposes or for a possible future refactoring of SQLObject. If it's > not of interest, just ignore. > > My thinking was triggered by: > - My wish for higher-level physical types that users construct > depending on the application > - My difficulties to easily add the things to SQLObject that I > expected to be easy: e.g., foreign keys... I feel confident that foreign keys are hard, and I'm okay with that. Which is to say -- the interface could use improvement (e.g., remove the double defining of the foreign key and the external join), but I don't think there's deep problems. > - I have an intuition (that I cannot materialize) that there is some > strong coupling in SqlObject that steepens the learning curve and > makes some behavior unintuitive. It may be that also the issues of > difficulties of subclassing etc. are falling in this area... As I > said, I have no overly clear ideas to offer. > > So my first product out of this is just a clarification of what > concepts (classes) there should be and how they relate with each > other. A first rough writeup of my ideas follows here: > > Concepts: > --------- > > Application Object: > An Application Object is independent of backend storage Independent of "backend storage", or independent of any particular backend storage that fits the rest of the model? I.e., independent like SQLObject currently is (by changing _connection), or something more (like, doesn't inherit from SQLObject)...? > Storable: > A superclass that makes application objects storable. > It adds methods that interact with the Backend in order to > - store > - update > - delete > the object > In addition, it provided methods to easily access related objects I can see how this might be stylistically different from the SQLObject class, but how is it otherwise different? (Well, there's SQLObject and MetaSQLObject, but those are tightly coupled, and I think justifiably so). SQLObject is tightly coupled to DBConnection (i.e., they chat a lot, there's no well defined interface between the two, and information that's available between the two of them isn't necessarily otherwise public). I can imagine them being decoupled, but only after SQLObject had a long time to mature. Now, SQLObject does place some restrictions on how you can create your classes, and some (though less) restrictions on the backend (the backend is less restricted because an RDBMS is already a much more restricted environment than Python). But SQLObject is *not* an OODBMS (with RDBMS backends). It's not ZODB or any of those... they use the RDBMS as a backend, where in SQLObject the Python class is more-or-less the slave to the RDBMS model and backend. There's a strong conceptual tie as well, which is a large benefit -- even if you let SQLObject create you schema, and don't touch the database except through SQLObject, you are using relational metaphors, which many people are comfortable with (and for more reasons than familiarity). Inheritance falls into this, IMHO. You can't support Python inheritance in an RDBMS. You can support something that vaguely approximates Python inheritance, and can solve some of the same problems, but it's not the same thing. But maybe you are really thinking of a super-superclass, i.e., something that SQLObject would inherit from, as well as other significantly different kinds of storage mechanisms. > Backend: > An object that manages the interaction with the actual database. > It has the following components: > - mapping > - dbDriver > - dbConnection > A first version can live with a single driver and connection--a later > version may be able to work with multiple databases > > Connection: > An actual connection or connection pool that interacts with the dbms > > DBdriver: > A class that provides functionality that depends on the kind of connection > used, typically depending on: > - dbms used (e.g., postgres) > - DBI module (and version) > The DBdriver supports a subset of dbCols BConnection is something of a misnomer -- DBDriver would probably be a better name (especially for the poorly named DBMConnection, which doesn't connect to anything). Well, in the beginning DBConnection was really just a primitive form of connection pool, but that part is relatively small now. There's nothing particularly important about the way they are joined. If they weren't, though, the interface would look pretty much the same (since the type of connection you make implies which DBDriver you would use). Separating DBConnection from DBDriver isn't a very significant change, since they are naturally coupled. Now, there is the possibility of different kinds of connection pooling and general connection usage, but that's orthogonal to both connections themselves, and the drivers for those connections. > Mapping: > Description of the physical representation in a dbms-independent way. > The mapping is described by the following components: > - Attributes of Storable Objects > - Relationships of Storable Objects Now, if I'm reading it right, this would be the most significant difference with SQLObject -- a mapping object is a separate from the class. But why? Hmm... on second thought I see a reason that while you would potentially define fields in the class, you may wish to define the way those map to a database separately. Then the class wouldn't be tied so much to SQLObject -- a very different kind of mapping could be used to take the same class and store it over SOAP. I still think the current definitions would be easier and clearer for most uses. At some point you may put it on a different backend, that may have different database names (for instance). Right now you could hack something together to do this by using a Style subclass that fed off a mapping table (instead of using algorithms to map names). But maybe I'm not clear on what you envision for mapping, since I would expect it would belong to the class (with the class having N mappings for N backends). I don't see how it would be part of the backend, so maybe you have something else in mind. > DbCol: > A low level physical type to represent a single field in the dbms. It is an > abstraction of the actual SQL type since different DBdrivers can map it to > different SQL expressions. The types are named closely to standard SQL. > Types such as TIMESTAMP could for example be translated to DateTime by a > mySQL dbDriver. Pretty much Col... > Attribute: > A high-level physical type to represent the higher-level physical rep. This > includes marshalling to and from a lower-level representation. Marshalling > can do things such as encoding structured objects (phone number with country > and area code) to strings, pickling, mapping a single attribute (a point) to > multiple columns (x, y or lat,long), etc. And something like this will come around at some point, it's just not developed yet. Ian |
From: Bud P. B. <bu...@si...> - 2003-05-09 09:29:18
Attachments:
backend-9.png
|
Hi Ian, many thanks for your feedback. I respond below.. On 08 May 2003 22:13:51 -0500 Ian Bicking <ia...@co...> wrote: > I feel confident that foreign keys are hard, and I'm okay with that. > Which is to say -- the interface could use improvement (e.g., remove the > double defining of the foreign key and the external join), but I don't > think there's deep problems. I'm experimenting a bit with my thoughts and yet have to figure out whether my intuitions verify. If I get some code to work, I'll send it and we'll talk about s.th. more concrete. What triggered my thinking was a difficulty that didn't match _my_ intuition--so maybe it reveals more about my thinking than it describes SQLObject.. > > Application Object: > > An Application Object is independent of backend storage > > Independent of "backend storage", or independent of any particular > backend storage that fits the rest of the model? > > I.e., independent like SQLObject currently is (by changing _connection), > or something more (like, doesn't inherit from SQLObject)...? In my thought experiment, I thought it would be nice to write a class without worries about persistance--just the business logic. In a second step (in my line of thought using inheritance), this is made persistant. This approach would make it possible to easily eachange persistance layers... But it is really more of a devide and conquer motivation... Not sure whether that is possible--but think for example of pre-existing classes that you want to make persistent.. > > Storable: > > A superclass that makes application objects storable. > > It adds methods that interact with the Backend in order to > > - store > > - update > > - delete > > the object > > In addition, it provided methods to easily access related objects > > I can see how this might be stylistically different from the SQLObject > class, but how is it otherwise different? (Well, there's SQLObject and > MetaSQLObject, but those are tightly coupled, and I think justifiably > so). Maybe this is not at all different from SQLObject??? Can I write a class and then make what I call a storable application class that inherits from both the business-logic-only class and SQLObject? > SQLObject is tightly coupled to DBConnection (i.e., they chat a lot, > there's no well defined interface between the two, and information > that's available between the two of them isn't necessarily otherwise > public). I can imagine them being decoupled, but only after SQLObject > had a long time to mature. I believe that my thoughts kind of split up DBConnection into several different entities (connection, dbdriver, and maybe also backend?). This way, I can for example define what I call mappings before opening an actual connection to the dbms. I see this as a sort of decoupling of components.. > Now, SQLObject does place some restrictions on how you can create your > classes, and some (though less) restrictions on the backend (the backend > is less restricted because an RDBMS is already a much more restricted > environment than Python). > > But SQLObject is *not* an OODBMS (with RDBMS backends). It's not ZODB > or any of those... they use the RDBMS as a backend, where in SQLObject > the Python class is more-or-less the slave to the RDBMS model and > backend. I believe I think along the same lines. I don't attempt to hide the RDBMS issues as an oodb would nor have I (so far) thought of hiding storage operations... (Again, I describe my thoughts and don't necessarily relate to SQLObject) I believe compared to SQLObject (which is difficult at my current vagueness of thought), I may have an additional abstraction layer between objects and the db, represented by the Attr class that implements my "higher-level" physical types. > There's a strong conceptual tie as well, which is a large > benefit -- even if you let SQLObject create you schema, and don't touch > the database except through SQLObject, you are using relational > metaphors, which many people are comfortable with (and for more reasons > than familiarity). > > Inheritance falls into this, IMHO. You can't support Python inheritance > in an RDBMS. Actually, some RDBMS such as PostgreSQL support inheritance. But I haven't thought of implementing inheritance much. I don't think along the lines of an oodbms such as Zope DB... > You can support something that vaguely approximates Python > inheritance, and can solve some of the same problems, but it's not the > same thing. I guess you're right. Haven't thought about this in detail. > But maybe you are really thinking of a super-superclass, i.e., something > that SQLObject would inherit from, as well as other significantly > different kinds of storage mechanisms. I don't think so, but I don't understand the super-super concept well... > > Backend: > > An object that manages the interaction with the actual database. > > It has the following components: > > - mapping > > - dbDriver > > - dbConnection > > A first version can live with a single driver and connection--a later > > version may be able to work with multiple databases > > > > Connection: > > An actual connection or connection pool that interacts with the dbms > > > > DBdriver: > > A class that provides functionality that depends on the kind of connection > > used, typically depending on: > > - dbms used (e.g., postgres) > > - DBI module (and version) > > The DBdriver supports a subset of dbCols > > BConnection is something of a misnomer -- DBDriver would probably be a > better name (especially for the poorly named DBMConnection, which > doesn't connect to anything). Well, in the beginning DBConnection was > really just a primitive form of connection pool, but that part is > relatively small now. There's nothing particularly important about the > way they are joined. If they weren't, though, the interface would look > pretty much the same (since the type of connection you make implies > which DBDriver you would use). Separating DBConnection from DBDriver > isn't a very significant change, since they are naturally coupled. I separated the two since it makes it possible to define mappings before having the connection in place. Trying to devide and conquer, I tried to separate the creation of SQL (strings) and actually communicating with the dmbs.. > Now, there is the possibility of different kinds of connection pooling > and general connection usage, but that's orthogonal to both connections > themselves, and the drivers for those connections. > > > Mapping: > > Description of the physical representation in a dbms-independent way. > > The mapping is described by the following components: > > - Attributes of Storable Objects > > - Relationships of Storable Objects > > Now, if I'm reading it right, this would be the most significant > difference with SQLObject -- a mapping object is a separate from the > class. But why? Yes, I believe this is probably the most significant change--probably at the core of what I call "weak coupling". A mapping just _describes_ the storage decisions made, doing nothing else at all. While decoupling was my prime motivation for thinking this way, it may also make it easier to cleanly separate representation decisions from the rest of the code, making it easier to modify, tune, etc. > Hmm... on second thought I see a reason that while you > would potentially define fields in the class, you may wish to define the > way those map to a database separately. Then the class wouldn't be tied > so much to SQLObject -- a very different kind of mapping could be used > to take the same class and store it over SOAP. Exactly > I still think the current definitions would be easier and clearer for > most uses. At some point you may put it on a different backend, that > may have different database names (for instance). Just my intuition, that could be wrong--but I think whether to separate or not has very little impact on the ease of defining the representation decisions. Something to verify.. My approach basically follows a pattern (maybe not in a formal sense) that I have used in other projects of mine: to represent just decisions as objects and separate how to act on those decisions in different classes.. > Right now you could hack something together to do this by using a Style > subclass that fed off a mapping table (instead of using algorithms to > map names). This surprises me. I see style and mapping as reasonably independent things. Style just defines some defaults (such as converting names form case sensitive to case insensitive) and if I chose an appropriate style, it saves me some typing. > But maybe I'm not clear on what you envision for mapping, since I would > expect it would belong to the class I believe that here we think differently. I explicitly want the mapping to live independently of the class. Maybe overly simplified, an object asks the backend to store it, the backend matches a mapping with the class of the object, asks the dbdriver to produce the appropriate sql (passing it mapping and object) and asking the connection to send it off... But the essence of decoupling is that the mapping is independent of the application class itself. Luke recently pointed to some Ambler articles and maybe my thoughts are influenced by that. The architecture Ambler describes actually keeps the mappings in an rdbms and offers an administration interface for mappings. Obviously, I don't attempt to go that far.. > (with the class having N mappings > for N backends). I don't see how it would be part of the backend, so > maybe you have something else in mind. The mapping is mostly independent of the dmbs used. So I don't see a need to keep multiple mappings for a given class for different backends. Backend, in my understanding of the concept, is a class that brings together some components (mapping, connection, dbdriver, etc) and knows how to make them play together. It provides the single interface to storable objects. A given object class will alway relate to a single backend; different classes may use different backends since, for example, their data resides in different dmbs... I suppose my quick writeup wasn't very clear... (bad, but difficult to avoid...) > > DbCol: > > A low level physical type to represent a single field in the dbms. It is > > an abstraction of the actual SQL type since different DBdrivers can map it > > to different SQL expressions. The types are named closely to standard > > SQL. Types such as TIMESTAMP could for example be translated to DateTime > > by a mySQL dbDriver. > > Pretty much Col... Yes, exactly. > > Attribute: > > A high-level physical type to represent the higher-level physical rep. > > This includes marshalling to and from a lower-level representation. > > Marshalling can do things such as encoding structured objects (phone > > number with country and area code) to strings, pickling, mapping a single > > attribute (a point) to multiple columns (x, y or lat,long), etc. > > And something like this will come around at some point, it's just not > developed yet. Great! So I hope my thoughts can help shape this... I have a little newer version of my class diagram that I attach in case you are interested in following the progress of my thoughts... thanks for the interesting discussion cheers --b |
From: Bud P. B. <bu...@si...> - 2003-05-12 15:41:06
|
On 08 May 2003 22:13:51 -0500 Ian Bicking <ia...@co...> wrote: > Now, if I'm reading it right, this would be the most significant > difference with SQLObject -- a mapping object is a separate from the > class. But why? Ian, I made some progress and I can more clearly answer to the question above: In this approach, relationships are instances managed by Mapping, not part of the "class" (of the storable application object). This way, to keep object references from the relationship object to the contained (from, to..) "table objects" (that I call ObjMap). I can also keep back-references from ObjMap to all the relations that reference it. This way, I avoid (at least it seems at the moment) all problems of circular dependencies, referencing to objects only by name, etc. --b /----------------------------------------------------------------- | Bud P. Bruegger, Ph.D. | Sistema (www.sistema.it) | Via U. Bassi, 54 | 58100 Grosseto, Italy | +39-0564-411682 (voice and fax) \----------------------------------------------------------------- |
From: Ian B. <ia...@co...> - 2003-05-12 23:16:26
|
On Mon, 2003-05-12 at 10:39, Bud P.Bruegger wrote: > > Now, if I'm reading it right, this would be the most significant > > difference with SQLObject -- a mapping object is a separate from the > > class. But why? > > Ian, I made some progress and I can more clearly answer to the > question above: > > In this approach, relationships are instances managed by Mapping, not > part of the "class" (of the storable application object). This way, > to keep object references from the relationship object to the > contained (from, to..) "table objects" (that I call ObjMap). I can > also keep back-references from ObjMap to all the relations that > reference it. > > This way, I avoid (at least it seems at the moment) all problems of > circular dependencies, referencing to objects only by name, etc. I'm still not really clear what you're thinking. Can you show how you might define a class, using a mapping? Ian |
From: Ian B. <ia...@co...> - 2003-05-15 15:44:33
|
Comments on at least a couple of your thoughts.. On Fri, 2003-05-09 at 04:28, Bud P.Bruegger wrote: > > > Storable: > > > A superclass that makes application objects storable. > > > It adds methods that interact with the Backend in order to > > > - store > > > - update > > > - delete > > > the object > > > In addition, it provided methods to easily access related objects > > > > I can see how this might be stylistically different from the SQLObject > > class, but how is it otherwise different? (Well, there's SQLObject and > > MetaSQLObject, but those are tightly coupled, and I think justifiably > > so). > > Maybe this is not at all different from SQLObject??? Can I write a > class and then make what I call a storable application class that > inherits from both the business-logic-only class and SQLObject? Certainly. > > SQLObject is tightly coupled to DBConnection (i.e., they chat a lot, > > there's no well defined interface between the two, and information > > that's available between the two of them isn't necessarily otherwise > > public). I can imagine them being decoupled, but only after SQLObject > > had a long time to mature. > > I believe that my thoughts kind of split up DBConnection into several > different entities (connection, dbdriver, and maybe also backend?). > This way, I can for example define what I call mappings before opening > an actual connection to the dbms. I see this as a sort of decoupling > of components.. I would expect mappings to be the equivalent of your SQLObject subclasses, which can be made independently of a database connection, or can use a simple connection like DBM when you are first writing things out. > > But maybe you are really thinking of a super-superclass, i.e., something > > that SQLObject would inherit from, as well as other significantly > > different kinds of storage mechanisms. > > I don't think so, but I don't understand the super-super concept > well... By that I mean that the SQLObject class, i.e., SQLObject inherits from Storable, and perhaps something ZODB-like would also inherit from Storable. Storable would implement a common interface for certain kinds of introspection necessary for persistence. > > BConnection is something of a misnomer -- DBDriver would probably be a > > better name (especially for the poorly named DBMConnection, which > > doesn't connect to anything). Well, in the beginning DBConnection was > > really just a primitive form of connection pool, but that part is > > relatively small now. There's nothing particularly important about the > > way they are joined. If they weren't, though, the interface would look > > pretty much the same (since the type of connection you make implies > > which DBDriver you would use). Separating DBConnection from DBDriver > > isn't a very significant change, since they are naturally coupled. > > I separated the two since it makes it possible to define mappings > before having the connection in place. Trying to devide and conquer, > I tried to separate the creation of SQL (strings) and actually > communicating with the dmbs.. Declaring a connection for a class is easy. Why is it a problem? Perhaps you're thinking of things like dbName, which map the Python columns to a particular schema. That's reasonable, but then if you are mapping to a legacy database then you probably know that from the beginning. > > Right now you could hack something together to do this by using a Style > > subclass that fed off a mapping table (instead of using algorithms to > > map names). > > This surprises me. I see style and mapping as reasonably independent > things. Style just defines some defaults (such as converting names > form case sensitive to case insensitive) and if I chose an appropriate > style, it saves me some typing. A hacked Style could handle changes to your dbNames, that's about it. Though when I think of a mapping, that's a large part. The other way would be to make a table-driven columnsFromSchema that was attached to your connection, and let that create the columns for you. Ian |
From: Ian B. <ia...@co...> - 2003-05-15 15:51:49
|
Just looking at your example below, doesn't this seem like a lot more work than SQLObject? What was two classes (Person and PhoneNumber), becomes seven (Person, PhoneNumber, StorablePerson, StorablePhoneNumber, a Person mapper, a PhoneNumber mapper, and a relation). I like that SQLObject's UML diagram (which doesn't exist, but let us imagine it) is a boring diagram, and that each class you use requires one class definition. On Tue, 2003-05-13 at 02:15, Bud P.Bruegger wrote: > So assume your app has a class Person, a class PhoneNumber, and a > 1:many relationship between them. So there would be the following > steps to make this storable: > > * make StorablePerson and StorablePhoneNumber with multiple > inheritance from Person and Storable, and PhoneNumber and Storable, > respectively. This would add methods to communicate with the > backend. Not sure yet, how I will do this--but hope to have some > initial code in a couple of days. > > * make a mapping objects that contains (aggregation) three major > subobjects: > - an ObjMap that basically represents the Person table > - an ObjMap that represents the PhoneNumber table > - a relationship object that defines the relationship between them > So a mapping has a set of "table definitions" and a set of > relationship definitions. "TableDefinitions" consist of a set of > attributes and attributes of a set of columns (in most cases just > one). > > * create a backend object by assembling a dbDriver, a dbConnection, > and the above mapping object. The dbDriver takes information > expressed in terms of mapping entities to create SQL statements > (strings). The connection sends these off... The backend object > manages all this. > > * storablePerson and storablePhoenNumber objects know about the > backend object and ask it to be stored, updated, deleted. The > backend first checks the class of the object and uses it to find the > according mapping (name match). Mapping and Driver produce the SQL > with variables for values, as well as marshal the python values of > the object for use in sql statments. > > * backend also provides finder methods that basically correspond to > select queries.. > > * backend shoudl also manage a cache and do some concurrancy > control... > > Hope this clarifies my ideas a little. > > best cheers > --b > > > On 12 May 2003 17:10:40 -0500 > Ian Bicking <ia...@co...> wrote: > > > On Mon, 2003-05-12 at 10:39, Bud P.Bruegger wrote: > > > > Now, if I'm reading it right, this would be the most significant > > > > difference with SQLObject -- a mapping object is a separate from the > > > > class. But why? > > > > > > Ian, I made some progress and I can more clearly answer to the > > > question above: > > > > > > In this approach, relationships are instances managed by Mapping, not > > > part of the "class" (of the storable application object). This way, > > > to keep object references from the relationship object to the > > > contained (from, to..) "table objects" (that I call ObjMap). I can > > > also keep back-references from ObjMap to all the relations that > > > reference it. > > > > > > This way, I avoid (at least it seems at the moment) all problems of > > > circular dependencies, referencing to objects only by name, etc. > > > > I'm still not really clear what you're thinking. Can you show how you > > might define a class, using a mapping? > > > > Ian > > > > > > > > > /----------------------------------------------------------------- > | Bud P. Bruegger, Ph.D. > | Sistema (www.sistema.it) > | Via U. Bassi, 54 > | 58100 Grosseto, Italy > | +39-0564-411682 (voice and fax) > \----------------------------------------------------------------- > |
From: Bud P. B. <bu...@si...> - 2003-05-16 03:31:37
|
I'm wondering, you may be right that my approach is more complex to the end user??? Hmmm, not easy to say... so let me try to make a concrete example that is similar to what you have in the doc: #-- the application classes ------------- class Person(object): pass class PhoneNumber(object): pass # I like the fact that these are totally independent... #-- making the above storable ------------------ personMap = ClassMap('Person', [ SimpleAttr('firstName', 'varchar', notNull=True, \ unique=True, length=100), SimpleAttr('middleInitial', 'char', notNull=True, \ unique=True, length=1), SimpleAttr('lastName', 'varchar', notNull=True, \ unique=True, length=100) ], \ tableName='perTab', idName='persid', autoSave=1) phoneMap = ClassMap('PhoneNumber', [ SimpleAttr('phoneNumber', 'varchar', notNull=True, \ length=14), SimpleAttr('phoneType', 'char', notNull=True, \ unique=True, length=1), SimpleAttr('lastName', 'varchar',length=5) ], autoSave=1) # what I don't have yet are specialized Attr subclasses (such as you # various Col subclasses. These could probably save some typing and # implement interesting semantics such as ENUM.. # also note that so far I don't deal with default values. They belong # in what I belive is the higher-level physical types that are # application dependent. I need to supply some base classes here to # make life easy. (Such as a nominal value class that is equiv to # ENUM) persPhoneRel = Many2Many(personMap, phoneMap, 'phoneNumbers') appMap = Mapping([personMap, phoneMap], [persPhoneRel]) conn= psycopg.connect(...) drv = PostgresPsycopgDriver() backend = Backend(drv, conn, appMap) #-------- and now everything is persistent --------- So yes, this may be a little more verbose than SQLObject and I suppose users are exposed to more classes. There is some room for making it more efficient for typing... But in any case, I don't see a big difference in complexity. [Obviously, I'm biased on this...] On 15 May 2003 10:52:26 -0500k Ian Bicking <ia...@co...> wrote: > Just looking at your example below, doesn't this seem like a lot more > work than SQLObject? What was two classes (Person and PhoneNumber), > becomes seven (Person, PhoneNumber, StorablePerson, StorablePhoneNumber, > a Person mapper, a PhoneNumber mapper, and a relation). > > I like that SQLObject's UML diagram (which doesn't exist, but let us > imagine it) is a boring diagram, and that each class you use requires > one class definition. > > On Tue, 2003-05-13 at 02:15, Bud P.Bruegger wrote: > > So assume your app has a class Person, a class PhoneNumber, and a > > 1:many relationship between them. So there would be the following > > steps to make this storable: > > > > * make StorablePerson and StorablePhoneNumber with multiple > > inheritance from Person and Storable, and PhoneNumber and Storable, > > respectively. This would add methods to communicate with the > > backend. Not sure yet, how I will do this--but hope to have some > > initial code in a couple of days. > > > > * make a mapping objects that contains (aggregation) three major > > subobjects: > > - an ObjMap that basically represents the Person table > > - an ObjMap that represents the PhoneNumber table > > - a relationship object that defines the relationship between them > > So a mapping has a set of "table definitions" and a set of > > relationship definitions. "TableDefinitions" consist of a set of > > attributes and attributes of a set of columns (in most cases just > > one). > > > > * create a backend object by assembling a dbDriver, a dbConnection, > > and the above mapping object. The dbDriver takes information > > expressed in terms of mapping entities to create SQL statements > > (strings). The connection sends these off... The backend object > > manages all this. > > > > * storablePerson and storablePhoenNumber objects know about the > > backend object and ask it to be stored, updated, deleted. The > > backend first checks the class of the object and uses it to find the > > according mapping (name match). Mapping and Driver produce the SQL > > with variables for values, as well as marshal the python values of > > the object for use in sql statments. > > > > * backend also provides finder methods that basically correspond to > > select queries.. > > > > * backend shoudl also manage a cache and do some concurrancy > > control... > > > > Hope this clarifies my ideas a little. > > > > best cheers > > --b > > > > > > On 12 May 2003 17:10:40 -0500 > > Ian Bicking <ia...@co...> wrote: > > > > > On Mon, 2003-05-12 at 10:39, Bud P.Bruegger wrote: > > > > > Now, if I'm reading it right, this would be the most significant > > > > > difference with SQLObject -- a mapping object is a separate from the > > > > > class. But why? > > > > > > > > Ian, I made some progress and I can more clearly answer to the > > > > question above: > > > > > > > > In this approach, relationships are instances managed by Mapping, not > > > > part of the "class" (of the storable application object). This way, > > > > to keep object references from the relationship object to the > > > > contained (from, to..) "table objects" (that I call ObjMap). I can > > > > also keep back-references from ObjMap to all the relations that > > > > reference it. > > > > > > > > This way, I avoid (at least it seems at the moment) all problems of > > > > circular dependencies, referencing to objects only by name, etc. > > > > > > I'm still not really clear what you're thinking. Can you show how you > > > might define a class, using a mapping? > > > > > > Ian > > > > > > > > > > > > > > > /----------------------------------------------------------------- > > | Bud P. Bruegger, Ph.D. > > | Sistema (www.sistema.it) > > | Via U. Bassi, 54 > > | 58100 Grosseto, Italy > > | +39-0564-411682 (voice and fax) > > \----------------------------------------------------------------- > > > > /----------------------------------------------------------------- | Bud P. Bruegger, Ph.D. | Sistema (www.sistema.it) | Via U. Bassi, 54 | 58100 Grosseto, Italy | +39-0564-411682 (voice and fax) \----------------------------------------------------------------- |
From: Bud P. B. <bu...@si...> - 2003-05-15 15:58:45
|
On 15 May 2003 10:45:20 -0500 Ian Bicking <ia...@co...> wrote: > Declaring a connection for a class is easy. Why is it a problem? It is easy once you know. When I first used it, I didn't understand why it wouldn't work and found out that I need the connection first. At least for me personally, decoupling connection and definition of the physical representation makes it easier to use, flattens the learning curve.. But I may be alone on this... > The other way would be to make a table-driven columnsFromSchema that was > attached to your connection, and let that create the columns for you. If I understand this correctly, ie, that you store the "object schema" that defines the mapping from python to SQL in tables, it comes very close to how I do it. Just that I am at a level where I represent the mapping as python objects--but it would be possible to write them out to a dbms and get them back into an object form.. cheers --b |
From: Ian B. <ia...@co...> - 2003-05-15 16:04:51
|
On Thu, 2003-05-15 at 10:57, Bud P.Bruegger wrote: > > Declaring a connection for a class is easy. Why is it a problem? > > It is easy once you know. When I first used it, I didn't understand > why it wouldn't work and found out that I need the connection first. > At least for me personally, decoupling connection and definition of > the physical representation makes it easier to use, flattens the > learning curve.. But I may be alone on this... Then that might just be a documentation issue. > > The other way would be to make a table-driven columnsFromSchema that was > > attached to your connection, and let that create the columns for you. > > If I understand this correctly, ie, that you store the "object schema" > that defines the mapping from python to SQL in tables, it comes very > close to how I do it. Just that I am at a level where I represent the > mapping as python objects--but it would be possible to write them out > to a dbms and get them back into an object form.. Well, I was thinking of something that's maybe a bit more hackish. Like: class MappingPostgresConnection(PostgresConnection): def __init__(self, mappings=None, **kw): self.mappings = mappings PostgresConnection(self, **kw) def columnsFromSchema(self, table, soClass): return self.mappings[soClass.__name__] myConnection = MappingPostgresConnection( mappings={'Person': [Col('name'), ...], 'PhoneNumber': [Col(...)]} Ian |