...
Code Block | ||
---|---|---|
| ||
void LoadDataloadTransactionData() { def ctx = api.getDatamartContext() def dm = ctx.getDatamart("Transactions") def q1 = ctx.newQuery(dm, true) q1.select("skuSku") q1.select("SUM(NetSales)", "SumNetSales ") q1.select("SUM(Cost)", "SumCost") q1.where(Filter.equal("skuSku", api.product("sku"))) api.global.queryData = ctx.executeQuery(q1).getData() } |
...
Code Block | ||
---|---|---|
| ||
DataUtil.LoadDataloadTransactionData() // fills api.global.queryData from query for (row in api.global.queryData) { row.ProfitMargin = (row.SumNetSales - row.SumCost) / row.SumNetSales } |
...
Code Block | ||
---|---|---|
| ||
def resultMatrix = api.newMatrix("SKU", "ProfitMargin") api.global.queryData.each { row -> resultMatrix.addRow(row.skuSku, row.ProfitMargin) } return resultMatrix |
...
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.
...
Instead, the above logic could be something like sothis:
DataUtil.groovy
Code Block | ||
---|---|---|
| ||
List<Map> GetDatagetTransactionData() { def ctx = api.getDatamartContext() def dm = ctx.getDatamart("Transactions") def q1 = ctx.newQuery(dm, true) q1.select("skuSku") q1.select("SUM(NetSales)", "SumNetSales ") q1.select("SUM(Cost)", "SumCost") q1.where(Filter.equal("skuSku", api.product("sku"))) return ctx.executeQuery(q1).getData() } |
...
Code Block | ||
---|---|---|
| ||
List<Map> data = DataUtil.GetDatagetTransactionData() // fills local variable from query for (row in data) ){ row.ProfitMargin = (row.SumNetSales - row.SumCost) / row.SumNetSales } return data |
...
Code Block | ||
---|---|---|
| ||
def resultMatrix = api.newMatrix("SKU", "ProfitMargin") out.ProcessData.each { row -> resultMatrix.addRow(row.skuSku, row.ProfitMargin) } return resultMatrix |
...
In this example, variables are passed explicitly using out.XX or using explicity 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:
...
Code Block | ||
---|---|---|
| ||
List<Map> GetDatagetTransactionData() { def ctx = api.getDatamartContext() def dm = ctx.getDatamart("Transactions") def q1 = ctx.newQuery(dm, true) q1.select("skuSku") q1.select("SUM(NetSales)", "SumNetSales ") q1.select("SUM(Cost)", "SumCost") q1.where(Filter.equal("skuSku", api.product("sku"))) return ctx.executeQuery(q1).getData() } api.global.queryData = GetDatagetData() |
ProcessData.groovy
Code Block | ||
---|---|---|
| ||
api.global.queryData.each { it ->
// do something
} |
This could be written much more effectively following the suggestions in the caching guide:
DataUtil.groovy
Code Block | ||
---|---|---|
| ||
List<Map> GetDatagetTransactionData() { return libs.SharedLib.CacheUtils.getOrSet("MyDataCacheKey"){ def ctx = api.getDatamartContext() def dm = ctx.getDatamart("Transactions") def q1 = ctx.newQuery(dm, true) q1.select("skuSku") q1.select("SUM(NetSales)", "SumNetSales ") q1.select("SUM(Cost)", "SumCost") q1.where(Filter.equal("skuSku", api.product("sku"))) return ctx.executeQuery(q1).getData() } } |
...
Code Block | ||
---|---|---|
| ||
List<Map> data = DataUtil.GetDatagetTransactionData() data.each { it -> // do something } |
...
Consider the following, where DataLibrary.groovy is a groovy Groovy library that can be called from any logic:
DataLibrary.groovy (library logic)
Code Block | ||
---|---|---|
| ||
List<Map> GetTransactionDatagetTransactionData() { def ctx = api.getDatamartContext() def dm = ctx.getDatamart("Transactions") def q1 = ctx.newQuery(dm, true) q1.select("skuSku") q1.select("SUM(NetSales)", "SumNetSales ") q1.select("SUM(Cost)", "SumCost") q1.where(Filter.equal("skuSku", api.product("sku"))) q1.where(Filter.equal("categoryCategory", api.getElement("Category"))) q1.where(Filter.greaterThan("netSalesNetSales", out.NetSalesMinimum)) q1.where(Filter.notIn("skuSku", api.global.exclusionSkus)) return ctx.executeQuery(q1).getData() } |
In this example, lines 10 - 1310–13, you can see there are 4 different variables being magically injected into the filters. While this might work when called from a pricelist price list logic where all of those scoped variables are present, it will never work for other logics where those scoped variables aren’t 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)
Code Block | ||
---|---|---|
| ||
List<Map> GetTransactionDatagetTransactionData(String sku, String category, Number netSalesMinimum, List<String> exclusionSkus) { def ctx = api.getDatamartContext() def dm = ctx.getDatamart("Transactions") def q1 = ctx.newQuery(dm, true) q1.select("skuSku") q1.select("SUM(NetSales)", "SumNetSales ") q1.select("SUM(Cost)", "SumCost") q1.where(Filter.equal("skuSku", sku)) q1.where(Filter.equal("categoryCategory", category)) q1.where(Filter.greaterThan("netSalesNetSales", netSalesMinimum)) q1.where(Filter.notIn("skuSku", exclusionSkus)) return ctx.executeQuery(q1).getData() } |
...