-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- RUNTIME EVALUATION OF RELATED FIELD SYNTAX AGAIN 96/01/12 Looking back over the way relationships work, it seems very convoluted at present. There's a lot of runtime evaluation on field access and the need for parens on related fields is annoying. This need seemed to be driven by ideals about having field expressions evaluated at runtime, given comments on 94/11/29 and similar dates. In particular, given circular relationships, you had to limit instantiation of related tables to avoid disappearing into a spiral at startup. Given an expression People.Visits->VisitDate, a simple approach would be to have People.Visits returning a pointer to a Visits object that contains fields that know they are related and to whom. KEY ISSUE We may only have one database extent (ie our prototypical dbPeople) in a connection, but we can have multiple selections on that database which implies multiple dbPeople objects. Thus, for each relationship, they theoretically have a separate related table each. The current philosophy is to only create these related tables when forced to by a relationship traversal. The map of the traversal is built by dbRelRef::operator-> and the traversal instantiation triggered by dbField::operator(). TODAY'S INSIGHT We can get the same result as the above, with very similar implementation, but avoid the need for the parens on the field expressions. The trick is: 1) Instead of building the map, the operator-> instantiates the relation (cloning the destination table) 2) The cloned fields of course know they are in a relationship. We already have dbField::validateContextInCaseRelated() called in all field accessors, so there is no modification on that side. FINALLY All relationship cloning propagation (for related selections) works the same way. That includes cloning descendant tables for inheritance. THE BIG POINT ???????? The immediate cloning for all relationships takes place at the definition of the prototypical (main extent) tables. GOTCHA One reason for accumulating the traversal path and instantiating in one go was to cater for other backends. It is entirely possible that an SQL backend or other database would provide this as an efficient native function! Step-by-step instantiation may break this. We can maybe work around this by having the step-by-step creation of dbTable clones all point to the traversal path anyway. (Something necessary for backtracking a related search.) We don't actually perform the data relation at each stage, just build a place-holder dbTable clone. When the field at the end of the expression executes dbField::validateContextInCaseRelated, each of these placeholder tables will perform its join. Following discussion with Ken, he agrees that this sounds feasible and is probably no more overhead than the current approach.