intersystems / intersystems/ipm
Routine database mappings not honored when deploying obj code
- Dominant language
- ObjectScript
- Stars
- 41
- Forks
- 29
- Avg merge
- 23h 54m
- Merged PRs (30d)
- 4
Description
The Issue in IPM
Summary: IPM doesn't honor routine database mappings when loading deployed (compiled-only) .obj code. It calls %Studio.Project:InstallFromFile() without directing output to the mapped database, causing .obj routines to land in the wrong database on systems where routine mappings point elsewhere.
Root Cause
In Document.cls:188
set sc = ##class(%Studio.Project).InstallFromFile(tDeployedProjectPath, "")
InstallFromFile with "" writes routines to the current namespace's default routine database. However, many deployments use routine mappings (via Config.MapRoutines) to direct specific routine prefixes to a different database — for example, a dedicated "driver" database. IPM is already aware of mappings (it has ResourceIsMappedToDefaultDB() at line 574 and can create mappings via %IPM.Utils.Module), but it doesn't use them when calling InstallFromFile.
On deployments where the mapped database differs from the default, the .obj routines get written to the wrong database on first install. A second install works because by then IPM's own mapping-setup phase has committed the mappings and the namespace resolves correctly.
Our Workaround
In our installer, we currently call InstallFromFile again after IPM's lifecycle completes, by which point mappings are guaranteed to be in place. This is brittle and duplicates work.
Suggested Improvement for IPM
Option A — Respect existing mappings during deployed-resource load:
Before calling InstallFromFile, IPM should ensure that any routine mappings declared in the module's module.xml are committed first. The lifecycle currently applies mappings in a separate phase (OnConfigureMappings), but the deployed-resource load can execute before that phase completes. Reordering so that mapping configuration runs before deployed resource loading would fix this without API changes.
Option B — Allow specifying a target database in the resource processor:
Add an optional Database attribute to elements in module.xml:
The Document processor would then switch to that database (or resolve via %SYS.Namespace:GetRoutineDest()) before calling InstallFromFile. This gives module authors explicit control without relying on namespace mappings being pre-configured.
Option C — Use GetRoutineDest() to resolve per-routine:
At line 188, instead of a single InstallFromFile call, iterate the deployed project's items, resolve each routine's mapped database via ##class(%SYS.Namespace).GetRoutineDest(, routineName), and load into the correct database. IPM already has this lookup logic in ResourceIsMappedToDefaultDB (line 574) — it just needs to apply it during load, not only for conflict detection.
Contributor guide
Research direction
Read Document.cls around line 188 and trace the deployed-resource lifecycle through OnConfigureMappings. Compare this path with ResourceIsMappedToDefaultDB at line 574 and the module.xml mapping declarations, then reproduce a first install where routine mappings target a non-default database. Done means deployed .obj routines land in their mapped database on the first install without a duplicate installer pass.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100