How to Merge Contents from Multiple Routine Databases into a Common Target Database
I am working on a tool that configures an instance to use a common default routine database across all custom Namespaces. For instances that already have distinct default routine databases for their Namespaces, this would involve a step of merging over all code from the current default routine databases to the new "super" routine database. This should be done in such a way that only merges contents in the default routine database (not mapped databases) and is able to detect/exclude contents that already exist in the target database.
Are there any supported tools/APIs for merging routine database contents to help accomplish this? I should clarify there is no guarantee as to what packages may or may not be present in the default routine databases and no guarantee as to what packages may be mapped from other databases. The goal is to allow a user to run this tool and be able to seamlessly access and run code previously stored in default routine databases from any of their custom Namespaces.
Comments
To merge the contents of multiple routine databases into a common target database, and ensure only routines in the default routine database (not mapped databases) are merged while excluding duplicates, several classes and APIs can assist in accomplishing this:
Use
%RoutineClass:%Routineclass provides methods to manipulate routines programmatically, such asRoutineExists(), which can be used to check if a routine already exists in the target database before merging.- Other relevant methods include
Compare(),RoutineList(), andSave()for exporting and saving routines. - This API supports creating, compiling, and modifying routines programmatically, making it suitable for tasks involving merging routine contents [1].
Use
%SYSTEM.OBJClass:- This class includes methods such as
Export(),ExportToStream(), andLoad()to facilitate the export and import of routines between databases. - These methods are useful for exporting routines from the source databases and loading them into the target database while managing duplicate entries by pre-checking if the routine exists using the
%Routineclass [1].
- This class includes methods such as
Routine Detection and Exclusion:
- You can programmatically query routines in the current default routine database and cross-check against the routines already present in the target database before importing, using classes like
%Routineand%RoutineIndexwhich provide routine information and indexing capabilities [1].
- You can programmatically query routines in the current default routine database and cross-check against the routines already present in the target database before importing, using classes like
Namespace Considerations:
- Routine mappings can be configured through the
Config.MapRoutinesclass or directly in the Management Portal. However, ensure that routine mappings in non-default databases are not mistakenly merged [1].
- Routine mappings can be configured through the
These tools allow for flexible and controlled merging of routine contents across databases, adhering to your requirements regarding default versus mapped databases and avoiding duplicates.
Relevant References:
- Tools and methods for working programmatically with routines [1].
Sources:
What about collisions?
Glad you asked, I would hope (depending on available tools/API) that there would be measures I could take to detect collisions and in that case do not merge the contents of that database with an informative message to the user that contents will need to be merged manually.
What are you trying to do with this that is not accomplished with shared library mapped databases like HSCOMMON?
A common mapped database is essentially the end result. The question here is not asking about the end result, but rather how we get there for an already existing system. Say we have a customer with an instance that already has a good deal of custom code across multiple databases. How do we move all of this code spread across multiple default routine databases to a single location so then all Namespaces can use a mapping to access it in one place?
DataMove might be useful for copying the routines once you have a. list of what to copy.
Tricky bit there is forming that list. DataMove seems to be per source Namespace rather than per source database. Is there a good way to get a list of all relevant contents from a specific routine database? This would be all classes, mac routines, int routines, projects, and more, but only those that are defined in the default routine database with care to not move mapped items.
You are right. $system.OBJ.Export~whatever is oriented to the Namespace
BUT:
There still seems to be no limitation to map a specific database file
to more than 1 namespace. e.g. USER and MERGER (here Read Only)
Then $system.OBJ.Export~whatever takes what it finds in MERGER.
It's quite a dirty approach and only meant for READING the code, therefore, ReadOnly
In any case, it's safer just to copy the (most likely static) DB of interest
and use it in MERGER
Very clever! Yes, I think I could create a Namespace that points to just the routine database of interest, merge over contents to target (since everything from that MERGER Namespace is desired), use this intermediary for each database of interest, then clean up at the end. Per Eduard's point above regarding conflicts, is there any way to pre-empt conflict using such tooling? If 2 databases have a class of the same name defined, how can I prevent clobbering the contents merged from the first database when I merge the second? Even if it is a conservative approach of failing to move code if there is any overlap, I think that would be preferable to overwriting existing code.
From Class Docs:
• classmethod ExportAllClassesIndividual(dirname As %String = "", qspec As %String = "", ByRef errorlog As %String, Charset As %String = "", Package As %String = "*", SubDir As %Boolean = 0) as %Status
Export all the classes as individual XML files to a directory.
This method loops through all the classes, exporting each one as an individual XML file named after the classname to the directory dirname. If you specify a Package, then it exports only this package. If SubDir is true,, the method exports sub-packages as subdirectories.
Now the directory is your list of classes and equal sizes of files
might most likely mean identical content. Or you do a text compare
I could do exports of contents from each database, accumulate these in a common directory only adding files if not already present, and then load everything in from this directory at the end. I was looking to avoid this approach if possible since I really just need database contents to move locally but if this needs to turn to OS file system exports, then that is a valid approach. I just need to be sure to export all of each item type that is present in the routine database (classes, routines, projects, etc) and import them using their respective APIs. Should a category of item that is stored in a routine database be added in the future I would need to account for this and explicitly add it to the list.