Burke, as I have written the code, it would work exactly like that. @Roger, can you add the next couple steps to this story, where we get into a scenario that my code shouldn't be able to handle?
-Darius On Wed, Apr 25, 2012 at 2:08 PM, Burke Mamlin <bmam...@regenstrief.org>wrote: > Ok, so if I want to create a drug order and a referral order for patient > with uuid 123-456, then request all orders for the patient, it would look > something like this (simplifying the order details for a simpler example)? > > *1. Create a drug order for my patient; they're built-in:* > POST order > { "patient":"123-456", "type":"drugorder", "order":"penicillin 500 mg > orally twice daily for 2 weeks" } > > *2. Install a module to add support for referral orders:* > Install a referrals module that adds a referralorder type of order. > Presumably, by introducing a new concept class for referral order, along > with a handler for the new order type and, of course, a ReferralOrder class > that extends Order. > > *3. Create a referral order for my patient:* > POST order > { "patient":"123-456", "type":"referralorder", "order":"cardiology > referral please evaluate for rheumatic heart disease" } > > *4. Find all the active orders for my patient:* > GET order?patient=123-456 > [ > { "patient":"123-456", "type":"drugorder", "order":"penicillin 500 mg > orally twice daily for 2 weeks", "uri":"…" }, > { "patient":"123-456", "type":"referralorder", "order":"cardiology > referral please evaluate for rheumatic heart disease", "uri":"…" } > ] > > Is that close? > > -Burke > > On Tue, Apr 24, 2012 at 9:21 PM, Darius Jazayeri > <djazayeri+...@gmail.com>wrote: > >> On RESTWS-243 <https://tickets.openmrs.org/browse/RESTWS-243> I've >> attached a patch that contains my implementation that I'm now ready to >> commit. (It's what Roger was responding to in his email.) >> >> I'm going to hold off on committing until after tomorrow's design call in >> case we have time to discuss this a bit. >> >> Basically what I've done is allow resources to indicate that they support >> subclasses, and if they do, they'll have all appropriate >> DelegatingSubclassHandlers registered with them via spring. >> >> The idea is that we're hiding subclasses from the consumer of the REST >> API. As far as they're concerned there is a single "order" resource, which >> has documents of different types (e.g. "order", "drugorder", etc.) Behind >> the scenes each type is a subclass, but in REST that's not visible, rather >> they're exposed as different document types. >> >> DelegatingSubclassHandler encapsulates the methods subclasses need to >> specify for their owning resource. >> >> Here is the functionality that my approach supports: >> >> *GET order* >> >> - gets all orders regardless of type >> - each document in the list may have different types >> - the top-level resource does the db query and delegates to the >> appropriate handler to convert each result >> >> *GET order?t=drugorder* >> >> - gets all orders whose type is drugorder >> - the subclass handler does the db query >> - In my implementation GET order?t=order (i.e. get only things that >> are order stubs) is not allowed >> >> *GET order?patient=<uuid>* >> >> - gets all orders for the given patient >> - each document in the list may have different types >> >> *GET order?patient=<uuid>&t=drugorder* >> >> - gets all orders for the given patient whose type is drugorder >> - if the subclass handler defines a suitable method, we use it, >> otherwise the top-level resource queries by patient, and manually filters >> out by type >> >> *GET order/<uuid>* >> >> - returns a specific order >> - representations are defined by the type, e.g. { "type": >> "drugorder", "dose": "100", ... } >> >> *POST order* >> >> - creates a new order >> - you must specify the type in the content, e.g. { "type": >> "drugorder", "dose": "100", ... } >> - allowed properties are defined by the type >> >> *POST order/<uuid>* >> >> - modifies an existing order >> - you are not allowed to change the type >> - allowed properties are defined by the type >> >> *DELETE order/<uuid>* >> >> - voids an order >> - handled by the top-level resource, not the subclass handler >> >> *DELETE order/<uuid>?purge=true* >> >> - purges an order >> - handled by the top-level resource, not the subclass handler >> >> @Roger, can you please phrase your counterproposal in terms of the >> additional functionality that you want to expose beyond these methods? >> >> -Darius >> >> >> On Mon, Apr 23, 2012 at 9:54 AM, Burke Mamlin <bmam...@regenstrief.org>wrote: >> >>> Roger, >>> >>> Could you provide some concrete examples? >>> >>> -Burke >>> >>> >>> On Mon, Apr 23, 2012 at 8:07 AM, Friedman, Roger (CDC/CGH/DGHA) (CTR) < >>> r...@cdc.gov> wrote: >>> >>>> AN ALTERNATIVE APPROACH TO SUBCLASS IMPLEMENTATION**** >>>> >>>> In this approach, subclass resources remain resources, just are mapped >>>> via the superclass. Substantially all operations are delegated to the >>>> appropriate subclass resource. This is motivated by simplicity, validation >>>> and representation considerations. It is also motivated by a privilege >>>> issue I just realized – the people authorized to create/update a lab order >>>> are likely different from those allowed to create/update a drug order. I >>>> have assumed that the privilege of updating a parent class field in >>>> subclass record requires only parent class privileges**** >>>> >>>> I don't believe this alternative requires much in the way of changes to >>>> existing code other than mappings; adding the controller and resource for >>>> each superclass; some changes in asRepresentation where it finds the right >>>> representation to use; and some changes where updates are going on to allow >>>> the possibility that the fields to be looked for in the request body may >>>> come from an object which is a parent class of the object being updated. It >>>> eliminates the need for the two variable lists used by Darius (although >>>> they could still be used if it was thought they added value). I still think >>>> it is a good idea to treat ActiveLists as an abstract class so that the >>>> AllergyList and the ProblemList appear to be two different superclasses. >>>> **** >>>> >>>> All members of a class hierarchy request a mapping to >>>> /<superclass>?t=<subclass>. The superclass also requests a mapping to >>>> /<superclass>?!t. I have tried to make all the calls of /<superclass>?!t >>>> work the same as calls to /<superclass>?t=<superclass>, if I have missed >>>> please let me know. It might be worthwhile to extend Resource to >>>> SuperclassResource to make the coding of the type-free calls easier. All >>>> representations include a t virtual field which contains the actual >>>> subclass of the object being represented.**** >>>> >>>> 1. GET <superclass>?t=<subclass>&v=<rep>, GET <superclass>?!t**** >>>> >>>> Purpose is to get all records of a particular subclass in a formatted >>>> representation. Spring routes this to the subclass controller. The subclass >>>> resource uses getAll to get a (polymorphic) list of objects. >>>> asRepresentation determines the class of each object and looks for the >>>> requested representation in that subclass resource; if it exists, it is >>>> used; if not, the parent class resource (if any) is searched for a >>>> representation; this continues until the t subclass has been searched, at >>>> which point a rep does not exist error is thrown.**** >>>> >>>> 2. GET <superclass>?t=<subclass>&v=<rep>&q=<search param>, GET >>>> <superclass>?!t&v=<rep>&q=<search param>**** >>>> >>>> Purpose is to use the standard query for a subclass to get a formatted >>>> representation. Spring routes this to the subclass controller. The subclass >>>> resource uses doSearch to get a (polymorphic) list of objects. >>>> asRepresentation determines the class of each object and looks for the >>>> requested representation in that subclass resource; if it exists, it is >>>> used; if not, the parent class resource (if any) is searched for a >>>> representation; this continues until the t subclass has been searched, at >>>> which point a rep does not exist error is thrown.**** >>>> >>>> 3. GET <superclass>?t=<subclass>&v=<rep>&<custom search>=<search param> >>>> **** >>>> >>>> Purpose is to do a custom search that is defined at some level of the >>>> class hierarchy. Spring routes this to the subclass controller. The >>>> subclass controller creates a resource for its type and delegates the >>>> search to it. The resource uses service methods to do the search to produce >>>> a (polymorphic) list of objects. asRepresentation determines the class of >>>> each object and looks for the requested representation in that subclass >>>> resource; if it exists, it is used; if not, the parent class resource (if >>>> any) is searched for a representation; this continues until the t subclass >>>> has been searched, at which point a rep does not exist error is thrown. >>>> **** >>>> >>>> 4. GET <superclass>/<uuid>?!t&v=<rep>**** >>>> >>>> Purpose is to get all records of a particular subclass in a formatted >>>> representation. Spring routes this to the superclass controller. The >>>> superclass resource uses getByUuid to get an object. asRepresentation >>>> determines the class of each object and looks for the requested >>>> representation in that subclass resource; if it exists, it is used; if not, >>>> the parent class resource (if any) is searched for a representation; this >>>> continues until the t subclass has been searched, at which point a rep does >>>> not exist error is thrown.**** >>>> >>>> 5. GET <superclass>/<uuid>?t=<subclass>&v=<rep>**** >>>> >>>> Purpose is to use a representation from a parent class. Like 5, except >>>> after getting by Uuid, the subclass resource coerces the result to be its >>>> type. asRepresentation determines the class of each object and looks for >>>> the requested representation in that subclass resource; if it exists, it is >>>> used; if not, the parent class resource (if any) is searched for a >>>> representation; this continues until the supertype has been searched, at >>>> which point a rep does not exist error is thrown.**** >>>> >>>> 6. POST <superclass>?t=<subclass> {body} >>>> >>>> Purpose is to create a new object of type <subclass>. The subclass >>>> resource creates a new object whose fields are extracted from the body (no >>>> need to know. The subclass resource save method uses services method to >>>> save the object; validation takes place in the save method. >>>> >>>> 7. POST <superclass>/<uuid>?!t {body}**** >>>> >>>> Purpose is to update an object of any subclass. The type is determined >>>> and the operation is delegated to the resource of the actual type.**** >>>> >>>> 8. POST <superclass/<uuid>?t=<subclass> {body}**** >>>> >>>> Purpose is to update an object using only parent-level fields. This is >>>> to avoid additional privileges at the actual subclass level. The type is >>>> deermined and the operation is delegated to the resource of the declared >>>> type. Throws an error if the actual type is not a subclass of the type >>>> declared. **** >>>> >>>> 9. DELETE <superclass>/<uuid>?!t&!purge, DELETE >>>> <superclass>/<uuid>?t=<subclass>&!purge**** >>>> >>>> Purpose is to delete an object of any subclass. The type is determined >>>> and the operation is delegated to the resource of the actual type. The >>>> subclass, if present, must match the actual type of the resource.**** >>>> >>>> 10. DELETE <superclass>/<uuid>?purge&!t, DELETE >>>> <superclass>/<uuid>?purge**** >>>> >>>> Purpose is to purge an object of any subclass. The type is determine >>>> and the operation is delegated to the resource of the actual type. The >>>> subclass, if present, must match the actual type of the resource.**** >>>> ------------------------------ >>>> Click here to >>>> unsubscribe<lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l>from >>>> OpenMRS Developers' mailing list >>> >>> >>> ------------------------------ >>> Click here to >>> unsubscribe<lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l>from >>> OpenMRS Developers' mailing list >>> >> >> ------------------------------ >> Click here to >> unsubscribe<lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l>from >> OpenMRS Developers' mailing list >> > > ------------------------------ > Click here to > unsubscribe<lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l>from > OpenMRS Developers' mailing list > _________________________________________ To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to lists...@listserv.iupui.edu with "SIGNOFF openmrs-devel-l" in the body (not the subject) of your e-mail. [mailto:lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l]