To program a migration you need to write code for its execute
block. The only parameter you have is m
, an SModule
,
and what you typically want is to search for all instances of a particular deprecated concept in all models of m
to
migrate them.
The straightforward way to do this is the following:
for (model mdl : m.getModels()) {
foreach node in mdl.nodes(MyDeprecatedConcept) {
// Do something with node
}
}
Note the two different kinds of for
loops. The for (type var : sequence)
loop lets me give the iteration variable
the more convenient model
type instead of using the SModel
type that would have been inferred by default. In the
second loop I don’t need this so I can use the simpler foreach
form.
There is also a second form that I have seen used in migrations. It looks like this:
with editable models in m do {
foreach node in #instances(MyDeprecatedConcept) {
// Do something with node
}
}
This form is slightly more flexible. In particular, it will automatically filter out non-editable models such as stubs, and you can specify whether you want to search for instances of the exact concept or include subconcepts.
I have also wondered whether the second form is more performant, but apart from the fact that it will skip non-editable
models, they seem to be equivalent. The code that is generated from the two forms of course looks very differently, yet
both forms use the same API in the end, FastNodeFinderManager.get(model).getNodes(concept, exact)
, and the non-exact
search will query for subconcepts of a particular concept using
ConceptDescendantsCache.getInstance().getDescendants(concept)
.
Skipping non-editable models will make a difference if you are going to migrate modules that contain migratable solutions together with stubs. I don’t think this makes a difference in practice so feel free to use the first form if you find it simpler to work with.