Re: [Modeling-users] API cleanup proposal
Status: Abandoned
Brought to you by:
sbigaret
From: Mario R. <ma...@ru...> - 2003-06-03 08:06:55
|
> Hi all, > > Here is a proposal to change some of the most commonly used methods; > the general idea is to improve developers' experience with the=20 > framework > by providing better, cleaner, shorter names for existing=20 > functionalities. I would also add "by indicating clearly the small subset of methods=20 intended for use by client code, and the stability level". > [Note on "most commonly used methods": I do not plan to change every > method's name when it's too long: they are mostly for the = framework's > use, or at best for advanced usage] > EditingContext (remember: an EC can be thought as a transaction) > -------------- > > - insert() instead of insertObject() > > - delete() instead of deleteObject() OK. What about commit() for saveChanges()? > - fetching: remove the need to import FetchSpecification and > Qualifier, and propose an alternate for > objectsWithFetchSpecification() > > def fetch(self, entityName, > qualifier=3DNone, # either a Qualifier instance or a=20= > string > orderBy=3DNone, # either a SortOrdering or a string > isDeep=3D0, # should subentities be fetched as=20= > well? > refresh=3D0, # unsupported yet > lock=3D0, # unsupported yet > limit=3DNone, # \ > page=3DNone, # > slice parameters, not in core = yet > offset=3DNone, # / (page/offset: mutually = exclusive) > ) > > Typical usage: > > ec.fetch('Writer', 'lastName ilike "hu?o"') > ec.fetch('Writer', 'age>=3D80"') > ec.fetch('Writer', 'author.pygmalion.lastName=20 > caseInsensitiveLike "r*"') > ec.fetch('Writer', orderBy=3D'firstName asc, lastName desc',=20 > isDeep=3D1) > ec.fetch('Books', orderBy=3D'title', limit=3D10, page=3D1) Yes, this is much easier than using FetchSpecification and=20 QualifierFormats... I feel that some things (even if no one has requested them yet ;) are=20 missing... for example, should one ever need to take advantage of sql "group by"=20 and "having". Access to these sql clauses may be added later, without breaking this=20 API, which is OK. Also, such manips may be done in the middle code, but that would be very inefficient. Another issue is that even with all the keyword options offered, one=20 still has to "dip into" small pieces of raw sql very quickly, as shown by your examples. This may be an acceptable compromise, but then client code should be allowed to pass any SQL it wants... Another detail is that the object loads all (direct) properties, every=20= time -- there may be no workaround for this, given the way the framework is=20 built. The real problem with this is that to request the result of an sql=20 function, of which count() is an example, additional api functionality is needed. But what happens if I want other functions, such as SUM or MAX or=20 AVERAGE over a few columns? Each of these functions may take complex parameters. Again, the functionality may be replicated in the middle code, but this=20= would not only be a waste of development time, but also be very inefficient. I propose either a generalization of "select" (which may be too=20 complicated in its implications), or an addition of a func keyword option, e.g. func=3D'count' func=3D('funcName', param1, param2, ...) func=3D( ('funcName', param1, param2, ...), ('funcname2') ) func=3D('sum','age') The question is then how is this information returned? I suggest as a tuple... Which reminds me that it would be nice to have a convenience "resultset" option, that when true returns results as a db resulset. This implies that one should not mix, in the same non-resultset fetch, requests for real objects and for additional "virtual" properties, such as counts, sums, etc. (Or stated differently, the presence of func will cause data to be returned as a tuple.) > - replace objectsCountWithFetchSpecification() with fetchCount() ? > [same API as fetch()] I propose use fetch() as descibed above: ec.fetch('Writer', qualifier=3D'age>=3D80"', func=3D'count') =3D> (3) but also: ec.fetch('Writer', qualifier=3D'age>=3D80"',=20 func=3D(('count'),('max','age'),('average','age')) ) =3D> (3,91,85) [ or else we can stick to raw sql: ec.fetch('Writer', qualifier=3D'age>=3D80"', func=3D'count(*), max(age),=20= average(age)' ) which may be simpler for everyone... in this case might as well change=20= 'func' to 'select', which will always assume a 'resulset' response ] > - replace (set)propagatesInsertionForRelatedObjects() with > autoInsertion() and setAutoInsertion() I prefer setAutoInsertion() > > CustomObject > ------------ > > I don't see any methods to change here. Maybe we could add=20 > globalID()? > However, the name itself 'CustomObject' could be changed if you have > some ideas (I admit it is not very representative of what it does, > i.e. defining generic methods for an object to be bound w/ the > framework) CustomObject will inherit the changes to the KeyValueCoding API, so it should be OK. CustomObject as name is not so bad. Other names that come to mind are MappedObject, ManagedObject, MorfedObject ;) PersistedObjected > Validation > ---------- > > Do we need to change anything there? validateValueForKey() is the > longest one, however I think this is not widely used, is it? I suggest validateProperty() instead of validateValueForKey(). > > KeyValueCoding > -------------- > > As Mario repeatedly pointed it out some time ago, this module needs=20= > to > be cleaned. > > Core methods: > > > | [public access] | [private access] > =20 > ------+---------------------------+---------------------------------- > [get] |valueForKey() | storedValueForKey() > |valueForKeyPath() | > =20 > ------+---------------------------+---------------------------------- > [set] |takeValueForKey() | takeStoredValueForKey() > |takeValueForKeyPath() | > =20 > ------+---------------------------+---------------------------------- > [dict]|takeValuesFromDictionary() |=20 > takeStoredValuesFromDictionary() > > Quick reminder: KVC is intensively used by the framework to get & = set > an object's values without knowing where it is > actually stored (for example, attribute 'name' can = be > stored in name, _name, and/or can be accessed/set = via > getters/setters name/getName()/setName()) > > The framework *always* uses the so-called "private" access > methods. The reason is that e.g. a public setter can have some > side-effect that should be triggered from a user's point of view (at > creation or modification time), but shouldn't be triggered when > object's data are fetched from the db (this is not very common, > though, hence I think we need a simplified and more efficient KVC = for > the common cases --off-topic here). > > This is my proposal: > > * getProp(name, path): > > getProp(key) replaces valueForKey(key) > getProp(path=3DkeyPath) replaces valueForKeyPath(keyPath) I like the use of path instead of another method. However does this imply an extra check per call? Also, when specified path must include name... is this better than path must never include name? > * setProp(name, path): > > setProp(key) replaces takeValueForKey(key) > setProp(path=3DkeyPath) replaces takeValueForKeyPath(keyPath) > > * same for getStoredProp() and setStoredProp() which replace > (take)storedValueForKey > > Notes: - parameters name & path are obviously mutually exclusive, > - get/setStoredProp shouldn't be needed from a developer's=20 > point > of view. > > * updateProps() replaces takeValuesFromDictionary() > updateStoredProps() replaces takeValuesFromStoredDictionary() OK for this, but I would in these case prefer to use the full word=20 (respecting the naming convention so far...), i.e.: co.getProperty() co.setProperty() co.getStoredProperty() co.setStoredProperty() co.updateProperties() co.updateStoredProperties() > Along with that, we also need an other module/class name for > KeyValueCoding. > > Mario proposed PropValueAccess. Any ideas? > GenericAccess?=20 > PropHandling? > I would be in favour of combining with RelationshipManipulation... > RelationshipManipulation > ------------------------ > > Any thoughts about how addObjectToBothSidesOfRelationshipWithKey()=20= > and > removeObjectFromBothSidesOfRelationshipWithKey() can be renamed? How about addViaRelation() and removeViaRelation() > =3D> An other solution could be: gather KVC and = RelationshipManipulation > in a single module, since they both address the same thing: generic > manipulation of an object, given its definition in the model. What=20= > do > you think? Yes. How about MappedObject PR? For Properties and Relations of course ;) Module name could be "mopr" or simply "opr". > BTW this is not a definitive list, just the things I know that need to > be changed. If you feel like changing other names please tell. > > > Your feedback is greatly appreciated!-) > > > -- S=E9bastien. mario |