Reminder: Create & find trunk-related issues here. Legacy Trac tickets are still available. Problems? Workflow feedback? Need a module project? Open a support ticket.

OpenMRS Trunk

Hierarchy of Locations

Details

  • Type: New Feature New Feature
  • Status: Closed Closed
  • Priority: Could Could
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: OpenMRS 1.5.0
  • Component/s: Data Model
  • Keywords:
  • Description:
    Hide

    Both PIH and implementations in Africa have asked for this. This can be accomplished similar to how roles are stacked.

    Along these lines, they also asked to tie city_village/state_province to the location table. This would allow them to create nice dropdown lists.

    Show
    Both PIH and implementations in Africa have asked for this. This can be accomplished similar to how roles are stacked. Along these lines, they also asked to tie city_village/state_province to the location table. This would allow them to create nice dropdown lists.
  1. location_hierarchy.2.patch
    (243 kB)
    Burke Mamlin
    2009-01-03 23:59:45 EST
  2. location_hierarchy.patch
    (66 kB)
    Burke Mamlin
    2008-11-25 00:50:27 EST
  3. locationHierarchyAndTags.patch
    (53 kB)
    Burke Mamlin
    2009-01-07 18:07:12 EST
  4. locationHierarchyAndTags_20090108.patch
    (54 kB)
    Burke Mamlin
    2009-01-08 17:02:39 EST
  5. locationHierarchyAndTags_20090131.patch
    (60 kB)
    Burke Mamlin
    2009-01-31 22:13:04 EST

Issue Links

Activity

Hide
Burke Mamlin added a comment - 2006-08-02 13:58:47 EDT

I fear that we're going to need to support several classes of locations – e.g., clinic locations, cities, states, etc. We don't want the list of all known villages to show up when data assistants are selecting a clinic site, right?

Show
Burke Mamlin added a comment - 2006-08-02 13:58:47 EDT I fear that we're going to need to support several classes of locations – e.g., clinic locations, cities, states, etc. We don't want the list of all known villages to show up when data assistants are selecting a clinic site, right?
Hide
Burke Mamlin added a comment - 2008-11-17 16:50:57 EST

+1 for Jeff's proposed solution:

<pre style="width:600px; overflow-x:scroll;padding:0.2em;border:thin solid black;background-color:#eee">
SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE {{location_type}} (
 {{location_type_id}} int(11) NOT NULL AUTO_INCREMENT,
 {{name}} varchar(50) NOT NULL DEFAULT '',
 {{description}} varchar(50) NOT NULL DEFAULT '',
 {{creator}} int(11) NOT NULL DEFAULT '0',
 {{date_created}} datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
 {{retired}} tinyint(1) NOT NULL DEFAULT '0',
 {{retired_by}} int(11) DEFAULT NULL,
 {{date_retired}} datetime DEFAULT NULL,
 {{retire_reason}} varchar(255) DEFAULT NULL,
 PRIMARY KEY ({{location_type_id}}),
 KEY {{location_type_name}} ({{name}}),
 KEY {{user_who_created_type}} ({{creator}}),
 KEY {{user_who_retired_encounter_type}} ({{retired_by}}),
 KEY {{retired_status}} ({{retired}}),
 CONSTRAINT {{user_who_created_type}} FOREIGN KEY ({{creator}}) REFERENCES {{users}} ({{user_id}}),
 CONSTRAINT {{user_who_retired_encounter_type}} FOREIGN KEY ({{retired_by}}) REFERENCES {{users}} ({{user_id}})
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE {{location}} ADD COLUMN {{parent_location_id}} int(11);
ALTER TABLE {{location}} ADD COLUMN {{location_type_id}} int(11);
ALTER TABLE {{location}} ADD KEY {{parent_location_for_location}} ({{parent_location_id}});
ALTER TABLE {{location}} ADD KEY {{type_of_location}} ({{location_type_id}});
ALTER TABLE {{location}} ADD CONSTRAINT {{parent_location}} FOREIGN KEY ({{parent_location_id}}) REFERENCES {{location}} ({{location_id}});
ALTER TABLE {{location}} ADD CONSTRAINT {{location_type}} FOREIGN KEY ({{location_type_id}}) REFERENCES {{location_type}} ({{location_type_id}});
SET FOREIGN_KEY_CHECKS=1;
</pre>
Show
Burke Mamlin added a comment - 2008-11-17 16:50:57 EST +1 for Jeff's proposed solution:
<pre style="width:600px; overflow-x:scroll;padding:0.2em;border:thin solid black;background-color:#eee">
SET FOREIGN_KEY_CHECKS=0;
CREATE TABLE {{location_type}} (
 {{location_type_id}} int(11) NOT NULL AUTO_INCREMENT,
 {{name}} varchar(50) NOT NULL DEFAULT '',
 {{description}} varchar(50) NOT NULL DEFAULT '',
 {{creator}} int(11) NOT NULL DEFAULT '0',
 {{date_created}} datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
 {{retired}} tinyint(1) NOT NULL DEFAULT '0',
 {{retired_by}} int(11) DEFAULT NULL,
 {{date_retired}} datetime DEFAULT NULL,
 {{retire_reason}} varchar(255) DEFAULT NULL,
 PRIMARY KEY ({{location_type_id}}),
 KEY {{location_type_name}} ({{name}}),
 KEY {{user_who_created_type}} ({{creator}}),
 KEY {{user_who_retired_encounter_type}} ({{retired_by}}),
 KEY {{retired_status}} ({{retired}}),
 CONSTRAINT {{user_who_created_type}} FOREIGN KEY ({{creator}}) REFERENCES {{users}} ({{user_id}}),
 CONSTRAINT {{user_who_retired_encounter_type}} FOREIGN KEY ({{retired_by}}) REFERENCES {{users}} ({{user_id}})
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE {{location}} ADD COLUMN {{parent_location_id}} int(11);
ALTER TABLE {{location}} ADD COLUMN {{location_type_id}} int(11);
ALTER TABLE {{location}} ADD KEY {{parent_location_for_location}} ({{parent_location_id}});
ALTER TABLE {{location}} ADD KEY {{type_of_location}} ({{location_type_id}});
ALTER TABLE {{location}} ADD CONSTRAINT {{parent_location}} FOREIGN KEY ({{parent_location_id}}) REFERENCES {{location}} ({{location_id}});
ALTER TABLE {{location}} ADD CONSTRAINT {{location_type}} FOREIGN KEY ({{location_type_id}}) REFERENCES {{location_type}} ({{location_type_id}});
SET FOREIGN_KEY_CHECKS=1;
</pre>
Hide
Andrey Kozhushkov added a comment - 2008-11-24 02:34:40 EST

I added a patch. Basically, it's what Jeff proposed, except types are now tags and have many-to-many mappings with locations.

  • added org.openmrs.LocationTag
  • org.openmrs.Location: added Set<Location> childLocations, Location parentLocation, Set<LocationTag> tags
  • added/extended hbm.xml
  • added db changes to sqldiff
  • extended API/DAO
  • refactored LocationServiceTest a bit, added LocationTag tests
  • added LocationServiceTest-initialData.xml
  • added new privs for LocationTag to OpenmrsConstants
Show
Andrey Kozhushkov added a comment - 2008-11-24 02:34:40 EST I added a patch. Basically, it's what Jeff proposed, except types are now tags and have many-to-many mappings with locations.
  • added org.openmrs.LocationTag
  • org.openmrs.Location: added Set<Location> childLocations, Location parentLocation, Set<LocationTag> tags
  • added/extended hbm.xml
  • added db changes to sqldiff
  • extended API/DAO
  • refactored LocationServiceTest a bit, added LocationTag tests
  • added LocationServiceTest-initialData.xml
  • added new privs for LocationTag to OpenmrsConstants
Hide
Andrey Kozhushkov added a comment - 2008-11-24 02:39:09 EST

Note:
Two of the JUnit assertion tests fail. One concens a three-tier Location hierarchy (parent->child->childofchild).

The other test fails to load child locations from the XML dataset, claiming the number of children is 0. I've had this problem with one of my modules before: JUnit tests failed while the webapp worked fine. I think JUnit might be having problems with hierarchies of the same class. Since the webapp parts of this extension are not implemented yet, I couldn't test that, obviously.

I've run out of ideas about these two errors, maybe someone else might have an idea...

Show
Andrey Kozhushkov added a comment - 2008-11-24 02:39:09 EST Note: Two of the JUnit assertion tests fail. One concens a three-tier Location hierarchy (parent->child->childofchild). The other test fails to load child locations from the XML dataset, claiming the number of children is 0. I've had this problem with one of my modules before: JUnit tests failed while the webapp worked fine. I think JUnit might be having problems with hierarchies of the same class. Since the webapp parts of this extension are not implemented yet, I couldn't test that, obviously. I've run out of ideas about these two errors, maybe someone else might have an idea...
Hide
Darius Jazayeri added a comment - 2008-11-24 11:16:44 EST

I think we also want a method:

Location.getChildLocations(boolean includeRetired);
Show
Darius Jazayeri added a comment - 2008-11-24 11:16:44 EST I think we also want a method:
Location.getChildLocations(boolean includeRetired);
Hide
Andrey Kozhushkov added a comment - 2008-11-25 00:50:27 EST

added Location.getChildLocations(includeRetired);

Show
Andrey Kozhushkov added a comment - 2008-11-25 00:50:27 EST added Location.getChildLocations(includeRetired);
Hide
Ben Wolfe added a comment - 2008-12-22 22:33:06 EST

Marking as Needs Review so that this is covered in one of our weekly code reviews.

Keelhaul: If you would like to join us while we look over this patch, let me know and we can schedule a day you can join us to walk through it. See http://openmrs.org/wiki/Code_Review_Schedule

Show
Ben Wolfe added a comment - 2008-12-22 22:33:06 EST Marking as Needs Review so that this is covered in one of our weekly code reviews. Keelhaul: If you would like to join us while we look over this patch, let me know and we can schedule a day you can join us to walk through it. See http://openmrs.org/wiki/Code_Review_Schedule
Hide
Ben Wolfe added a comment - 2009-01-02 20:56:58 EST

Keelhaul: I can't get this to apply to the latest trunk cleanly. What are the chances you still have these changes and can do an "svn update" and attach a new patch?

Show
Ben Wolfe added a comment - 2009-01-02 20:56:58 EST Keelhaul: I can't get this to apply to the latest trunk cleanly. What are the chances you still have these changes and can do an "svn update" and attach a new patch?
Hide
Andrey Kozhushkov added a comment - 2009-01-02 23:37:39 EST

Do the error occur when applying sqldiff changes, by chance? I assigned a db version to my changes manually. If the db has had any updates since 11/25, then this might be causing errors?

Do you want me to update my trunk with the changes applied, and then create a new patch off that?

Show
Andrey Kozhushkov added a comment - 2009-01-02 23:37:39 EST Do the error occur when applying sqldiff changes, by chance? I assigned a db version to my changes manually. If the db has had any updates since 11/25, then this might be causing errors? Do you want me to update my trunk with the changes applied, and then create a new patch off that?
Hide
Andrey Kozhushkov added a comment - 2009-01-04 00:03:27 EST

I re-created the patch after an update from svn. Seems to integrate properly into an untouched trunk and compile. Prior to that, however, updating from svn broke my locally edited files (duplicate methods, svn tags e.g. "<<<<< .mine" or something like that, etc.). Had to fix them manually to resolve the conflicts.

Show
Andrey Kozhushkov added a comment - 2009-01-04 00:03:27 EST I re-created the patch after an update from svn. Seems to integrate properly into an untouched trunk and compile. Prior to that, however, updating from svn broke my locally edited files (duplicate methods, svn tags e.g. "<<<<< .mine" or something like that, etc.). Had to fix them manually to resolve the conflicts.
Hide
Ben Wolfe added a comment - 2009-01-06 21:35:48 EST

The patch now applied quite cleanly, thanks!

FYI, those "<<< .mine" lines in there are svn specific. The proper way to resolve those conflicts is to use "Team->edit conflicts", save the "merged" file, then do "team->mark resolved" 'fix' the files.

When you get a chance, can you re-do the location table sql update in liquibase xml format and put it into the liquibase-update-to-latest.xml file?

Show
Ben Wolfe added a comment - 2009-01-06 21:35:48 EST The patch now applied quite cleanly, thanks! FYI, those "<<< .mine" lines in there are svn specific. The proper way to resolve those conflicts is to use "Team->edit conflicts", save the "merged" file, then do "team->mark resolved" 'fix' the files. When you get a chance, can you re-do the location table sql update in liquibase xml format and put it into the liquibase-update-to-latest.xml file?
Hide
Ben Wolfe added a comment - 2009-01-07 18:07:12 EST

Slightly modified Keelhaul's patch to save locations and execute test cases

Show
Ben Wolfe added a comment - 2009-01-07 18:07:12 EST Slightly modified Keelhaul's patch to save locations and execute test cases
Hide
Ben Wolfe added a comment - 2009-01-07 18:36:45 EST

Keelhaul: I've attached a patch that has the fixes for the test cases you mentioned. It entailed making a change to the HibernateLocationDAO.saveLocation to work like HibernateObsDAO.saveObs worked. Luckily, I had encountered the same problem when I was doing obs grouping, so I knew where to look.

The other fix was in trunk. The "parent_location_id" column was not being picked up in your dbunit xml file because the first location element in there didn't have that column defined. For some reason, dbunit treats the first element as the standard for all elements in that file. Because the first element didn't have the column, the column wasn't used in any of the subsequent elements...hence your other columns not really being children of the parent. I added the column to the first with a value of [NULL] so that it would work. Update to the latest trunk as well.

Two requests:

  1. Have LocationTag mimic ConceptNameTag. The properties on it should be the same, saved the same way, etc. (You don't need those default values though)
  2. Clean up and shorten your test cases. I really like where you're going with the test cases. Kudos to you for it! However, some of your test cases are doing too much, assert more than once, etc. You can pull a lot of tests out into really small LocationTest.java and only test, say, the addChildLocation(Location) method. Then in your LocationServiceTest you can assume that that will be working and you won't have to do so many asserts.
    Something like:
    LocationTest.java:
    public void addChildLocation_shouldAssignParentLocation() \{
      Location parentLocation = new Location();
      Location childLocation = new Location();
      parentLocation.addChildLocation(childLocation);
      assertTrue(parentLocation.equals(childLocation.getParentLocation()));
    \}

Strong work here, Keelhaul. Once you throw in these changes, we'll push it through an official code review and hopefully get it into trunk soon!

I'll add a liquibase element for the sql changes for you when I can...

Show
Ben Wolfe added a comment - 2009-01-07 18:36:45 EST Keelhaul: I've attached a patch that has the fixes for the test cases you mentioned. It entailed making a change to the HibernateLocationDAO.saveLocation to work like HibernateObsDAO.saveObs worked. Luckily, I had encountered the same problem when I was doing obs grouping, so I knew where to look. The other fix was in trunk. The "parent_location_id" column was not being picked up in your dbunit xml file because the first location element in there didn't have that column defined. For some reason, dbunit treats the first element as the standard for all elements in that file. Because the first element didn't have the column, the column wasn't used in any of the subsequent elements...hence your other columns not really being children of the parent. I added the column to the first with a value of [NULL] so that it would work. Update to the latest trunk as well. Two requests:
  1. Have LocationTag mimic ConceptNameTag. The properties on it should be the same, saved the same way, etc. (You don't need those default values though)
  2. Clean up and shorten your test cases. I really like where you're going with the test cases. Kudos to you for it! However, some of your test cases are doing too much, assert more than once, etc. You can pull a lot of tests out into really small LocationTest.java and only test, say, the addChildLocation(Location) method. Then in your LocationServiceTest you can assume that that will be working and you won't have to do so many asserts. Something like:
    LocationTest.java:
    public void addChildLocation_shouldAssignParentLocation() \{
      Location parentLocation = new Location();
      Location childLocation = new Location();
      parentLocation.addChildLocation(childLocation);
      assertTrue(parentLocation.equals(childLocation.getParentLocation()));
    \}
Strong work here, Keelhaul. Once you throw in these changes, we'll push it through an official code review and hopefully get it into trunk soon! I'll add a liquibase element for the sql changes for you when I can...
Hide
Andrey Kozhushkov added a comment - 2009-01-08 17:08:46 EST

I renamed some members and added a few methods to the LocationTag class to match those of ConceptNameTag. Renamed a few getLocationTag* methodss in the service/dao. However, ConceptService has only a 2 or 3 methods for ConceptNameTag, all others are missing.

As for the unit tests, I got rid of the asserts that have nothing to do with the operations performed by the service. No LocationTest yet, though.

Is that sufficient?

Show
Andrey Kozhushkov added a comment - 2009-01-08 17:08:46 EST I renamed some members and added a few methods to the LocationTag class to match those of ConceptNameTag. Renamed a few getLocationTag* methodss in the service/dao. However, ConceptService has only a 2 or 3 methods for ConceptNameTag, all others are missing. As for the unit tests, I got rid of the asserts that have nothing to do with the operations performed by the service. No LocationTest yet, though. Is that sufficient?
Hide
Darius Jazayeri added a comment - 2009-01-27 17:15:09 EST

To-Do items arising from code review on Jan 26, 2009, by Darius and Ben.

  • LocationService.java
  • getLocationsByTags -> split into two methods, getLocationsHavingAllTags and getLocationsHavingAnyTag
  • also add a getLocationsByTag that takes a single tag.
  • findLocationTags(String) should be renamed to getLocationTags(String), and carry that name change through to the DAO.
  • getLocationTagById(Integer) should be renamed to getLocationTag(Integer), and carry that name change through to the DAO.
  • OpenmrsConstants.java
  • Remove PRIV_VIEW_LOCATION_TAGS and use PRIV_VIEW_LOCATIONS instead.
  • LocationServiceImpl.java
  • populateMetadata should take a User and Date arguments so that you can just do "new Date()" once, and make use that identical timestamp for all children.
  • SQL for location_tag table
  • make 'name' column unique.
  • HibernateLocationDAO.java
  • in findLocationTags(String) method, the "if (search == null ..." should be pushed up to the ServiceImpl instead.
  • Everywhere
  • all non-trivial methods need @should annotations in their javadoc. Ben can tell you where to get the cool eclipse plugin that will help with this.
  • Location.java
  • getChildLocations(boolean)
  • javadoc should say "child.parentLocationId = this.locationId"
  • Remove the "not used often" bit.
  • if (includeRetired) ... else ... part actually only gets called one way, because it's surrounded by another if. Fix this.
  • addChildLocation(Location)
  • should check all the way up the heirarchy for loops, not just the direct parent
  • Also check to make sure this != child, i.e. we aren't marking something as its own child.
  • take out the two convenience methods for addTag(String) and addTag(String, String)
  • add unit tests for calling Location.addTag and then doing a LocationService.saveLocation, and ensure correct behavior for creating a new transient "new LocationTag()" that isn't yet persisted.
  • I propose you are not allowed to use transient tags, but feel free to disagree.
  • remove hasTag(LocationTag) (having that delegate based on just String name is wrong)
  • have isRetired() delegate directly to getRetired(). (retired won't be null)

We haven't looked at the unit tests yet, but will after these issues are addressed.

Thanks for doing this!

Show
Darius Jazayeri added a comment - 2009-01-27 17:15:09 EST To-Do items arising from code review on Jan 26, 2009, by Darius and Ben.
  • LocationService.java
  • getLocationsByTags -> split into two methods, getLocationsHavingAllTags and getLocationsHavingAnyTag
  • also add a getLocationsByTag that takes a single tag.
  • findLocationTags(String) should be renamed to getLocationTags(String), and carry that name change through to the DAO.
  • getLocationTagById(Integer) should be renamed to getLocationTag(Integer), and carry that name change through to the DAO.
  • OpenmrsConstants.java
  • Remove PRIV_VIEW_LOCATION_TAGS and use PRIV_VIEW_LOCATIONS instead.
  • LocationServiceImpl.java
  • populateMetadata should take a User and Date arguments so that you can just do "new Date()" once, and make use that identical timestamp for all children.
  • SQL for location_tag table
  • make 'name' column unique.
  • HibernateLocationDAO.java
  • in findLocationTags(String) method, the "if (search == null ..." should be pushed up to the ServiceImpl instead.
  • Everywhere
  • all non-trivial methods need @should annotations in their javadoc. Ben can tell you where to get the cool eclipse plugin that will help with this.
  • Location.java
  • getChildLocations(boolean)
  • javadoc should say "child.parentLocationId = this.locationId"
  • Remove the "not used often" bit.
  • if (includeRetired) ... else ... part actually only gets called one way, because it's surrounded by another if. Fix this.
  • addChildLocation(Location)
  • should check all the way up the heirarchy for loops, not just the direct parent
  • Also check to make sure this != child, i.e. we aren't marking something as its own child.
  • take out the two convenience methods for addTag(String) and addTag(String, String)
  • add unit tests for calling Location.addTag and then doing a LocationService.saveLocation, and ensure correct behavior for creating a new transient "new LocationTag()" that isn't yet persisted.
  • I propose you are not allowed to use transient tags, but feel free to disagree.
  • remove hasTag(LocationTag) (having that delegate based on just String name is wrong)
  • have isRetired() delegate directly to getRetired(). (retired won't be null)
We haven't looked at the unit tests yet, but will after these issues are addressed. Thanks for doing this!
Hide
Andrey Kozhushkov added a comment - 2009-01-27 21:53:57 EST

Do you want all PRIV_*_LOCATION_TAGS privs removed or just VIEW?

Show
Andrey Kozhushkov added a comment - 2009-01-27 21:53:57 EST Do you want all PRIV_*_LOCATION_TAGS privs removed or just VIEW?
Hide
Ben Wolfe added a comment - 2009-01-27 22:51:37 EST

just VIEW

Show
Ben Wolfe added a comment - 2009-01-27 22:51:37 EST just VIEW
Hide
Andrey Kozhushkov added a comment - 2009-01-31 22:15:15 EST

Ok, I think I've cleared that list. I cannot get JUnit tests to run properly anymore though, so everything is untested. =(

I agree with the no transient tags policy. Added a check when saving a location (match the name with an existing tag and overwrite, otherwise throw an exception).

Show
Andrey Kozhushkov added a comment - 2009-01-31 22:15:15 EST Ok, I think I've cleared that list. I cannot get JUnit tests to run properly anymore though, so everything is untested. =( I agree with the no transient tags policy. Added a check when saving a location (match the name with an existing tag and overwrite, otherwise throw an exception).
Hide
Justin Miranda added a comment - 2009-02-23 20:56:34 EST

Code reviewed on 23 Feb 2009.

Comments:

  • (TODONOT) 298-299: remove call to getAllLocationTags(true) when passed null or empty string. Discussed - we're going to keep this for now.
  • (TODO) 85: change "tag = existing" to do a remove(tag), add(tag) similar to how the concept name tag code works (see ConceptServiceImpl 1152)
  • Darius brought up the issue of location hierarchy changes.
  • (TODO) Need to come up with a specific use case.
Show
Justin Miranda added a comment - 2009-02-23 20:56:34 EST Code reviewed on 23 Feb 2009. Comments:
  • (TODONOT) 298-299: remove call to getAllLocationTags(true) when passed null or empty string. Discussed - we're going to keep this for now.
  • (TODO) 85: change "tag = existing" to do a remove(tag), add(tag) similar to how the concept name tag code works (see ConceptServiceImpl 1152)
  • Darius brought up the issue of location hierarchy changes.
  • (TODO) Need to come up with a specific use case.
Hide
Justin Miranda added a comment - 2009-02-23 20:57:53 EST

FYI, Ben is going to make the change(s) in the comments from the code review. Darius is going to get back to us on whether we need to worry about tracking changes for location hierarchy.

Show
Justin Miranda added a comment - 2009-02-23 20:57:53 EST FYI, Ben is going to make the change(s) in the comments from the code review. Darius is going to get back to us on whether we need to worry about tracking changes for location hierarchy.
Hide
Darius Jazayeri added a comment - 2009-02-23 21:14:15 EST

Mike and I discussed this and decide that the right way to do things would be to have a table like:

create table location_hierarchy_map (
   id integer primary key,
   parent_location_id not null references location,
   child_location_id not null references location,
   start_date date, -- can be null, this is when this hierarchy becomes effective
   end_date date -- can be null, this is when this hierarchy stops being effective
);

This would allow two things, both of which we've seen in practice:

  • capture the fact that administrative districts change (we've seen this in both Rwanda and Peru)
  • capture the fact that their can be multiple sets of location groupings. (In Peru there are 'health districts' and 'administrative districts' which don't line up exactly. A clinic is in one health district, and one administrative district.)

In practice this flexibility is not needed right now, so it probably makes sense to commit the location hierarchy patches as keelhaul has implemented them, and switch the data model around a year down the road when someone has a specific use case.

It is worth considering leaving the service methods exactly as keelhaul has defined them, but using a many-to-many mapping table instead of just the parent ref back to location, such that making a change in the future to support multiple hierarchies and history of changes is easier.

Show
Darius Jazayeri added a comment - 2009-02-23 21:14:15 EST Mike and I discussed this and decide that the right way to do things would be to have a table like:
create table location_hierarchy_map (
   id integer primary key,
   parent_location_id not null references location,
   child_location_id not null references location,
   start_date date, -- can be null, this is when this hierarchy becomes effective
   end_date date -- can be null, this is when this hierarchy stops being effective
);
This would allow two things, both of which we've seen in practice:
  • capture the fact that administrative districts change (we've seen this in both Rwanda and Peru)
  • capture the fact that their can be multiple sets of location groupings. (In Peru there are 'health districts' and 'administrative districts' which don't line up exactly. A clinic is in one health district, and one administrative district.)
In practice this flexibility is not needed right now, so it probably makes sense to commit the location hierarchy patches as keelhaul has implemented them, and switch the data model around a year down the road when someone has a specific use case. It is worth considering leaving the service methods exactly as keelhaul has defined them, but using a many-to-many mapping table instead of just the parent ref back to location, such that making a change in the future to support multiple hierarchies and history of changes is easier.
Hide
Ben Wolfe added a comment - 2009-02-23 21:27:26 EST

So leave the Location object as only having a single parent but add a table to store multiple parents? I don't think thats really worth it. I feel like adding a table, etc later on will be trivial. Having an unnecessary table in there for a year or so isn't really worth it.

Show
Ben Wolfe added a comment - 2009-02-23 21:27:26 EST So leave the Location object as only having a single parent but add a table to store multiple parents? I don't think thats really worth it. I feel like adding a table, etc later on will be trivial. Having an unnecessary table in there for a year or so isn't really worth it.
Hide
Darius Jazayeri added a comment - 2009-02-25 05:59:09 EST

I think it's okay to commit as-is. We can revisit later once there's a real need.

-Darius

Show
Darius Jazayeri added a comment - 2009-02-25 05:59:09 EST I think it's okay to commit as-is. We can revisit later once there's a real need. -Darius
Hide
Ben Wolfe added a comment - 2009-02-25 14:47:01 EST

Ok, committed to trunk in rev:6984 and will be included in the 1.5 release.

See ticket TRAC-1287 for adding the user interface portions of hierarchies + tags.

Show
Ben Wolfe added a comment - 2009-02-25 14:47:01 EST Ok, committed to trunk in rev:6984 and will be included in the 1.5 release. See ticket TRAC-1287 for adding the user interface portions of hierarchies + tags.

People

Dates

  • Created:
    2006-08-02 12:57:48 EDT
    Updated:
    2010-07-09 01:30:36 EDT
    Resolved:
    2010-07-01 22:39:55 EDT