Injected Variables & Passing Between Libs / Elements
It is common that you will need to pass variables between elements, and there are a number of ways to do this. Some ways are more readable than others, so consider the maintainability of how you do this.
Â
Magic Globals
api.global and api.local are very useful mechanisms for caching data, but accessing & mutating entries inside them between multiple elements quickly gets messy.
Consider the following:
DataUtil.groovy
void loadTransactionData() {
def ctx = api.getDatamartContext()
def dm = ctx.getDatamart("Transactions")
def q1 = ctx.newQuery(dm, true)
q1.select("Sku")
q1.select("SUM(NetSales)", "SumNetSales")
q1.select("SUM(Cost)", "SumCost")
q1.where(Filter.equal("Sku", api.product("sku")))
api.global.queryData = ctx.executeQuery(q1).getData()
}
ProcessData.groovy
DataUtil.loadTransactionData() // fills api.global.queryData from query
for (row in api.global.queryData) {
row.ProfitMargin = (row.SumNetSales - row.SumCost) / row.SumNetSales
}
ResultMatrix.groovy
def resultMatrix = api.newMatrix("SKU", "ProfitMargin")
api.global.queryData.each { row ->
resultMatrix.addRow(row.Sku, row.ProfitMargin)
}
return resultMatrix
Â
In the first element, the code creates a List<Map> and adds it to api.global. Not too bad, but not ideal.
In the next element, the code directly references that list (bad) and then modifies data in the list (awful).
In the third element, the code directly references the list again in api.global and presents the values into a matrix.
Â
This is a simple example, with only 3 sequential elements. Now imagine 100+ calculation elements, that call external libs, all of which might create/mutate data inside api.global. Debugging & refactoring this kind of code is almost impossible.
Â
Instead, the above logic could be something like this:
DataUtil.groovy
ProcessData.groovy
ResultMatrix.groovy
Â
In this example, variables are passed explicitly using out.XX or using explicitly method calls.
This code is much easier to debug and refactor than the first version.
api.global for Caching
Consider the same example as above where we need to cache the result of the query data:
DataUtil.groovy
ProcessData.groovy
Â
This could be written much more effectively following the suggestions in the caching guide:
DataUtil.groovy
ProcessData.groovy
Â
In this example, we can call DataUtil.GetData()
as many times as we want without consequence. The first time it is called, it will run the query and cache the result. Every other time we call it, the result will simply return directly from the cache and not re-process.
Using this strategy, we have an explicit sequence of events. It is very easy to see where the data came from, and debug/refactor it.
Injected Scoped Variables in Lib Methods
Consider the following, where DataLibrary.groovy is a Groovy library that can be called from any logic:
DataLibrary.groovy (library logic)
Â
In this example, lines 10–13, you can see there are 4 different variables being magically injected into the filters. While this might work when called from a price list logic where all of those scoped variables are present, it will never work for other logics where those scoped variables are not present.
Instead, this lib method should use method parameters, so it can be easily reused by any other piece of code like so:
DataLibrary.groovy (library logic)
Â
Found an issue in documentation? Write to us.
Â