In addition to being able to easily create integrations to back end data sources, Arrow provides several facilitates for moving data manipulation and processing operations from the client application to the Arrow server. This results in a mobile application that is more highly performant since data manipulations and computations do not need to be performed in the application. Implementing business logic and computations in the server, instead of in the mobile application, makes changes simpler, since a new mobile application does not need to be published when business logic/rules change.
Read more about Arrow here.
###Use Case
Consider a simple use case of an app for displaying actual vs forecast sales data that is retrieved from a Microsoft SQL or MySQL staging Database.
Arrow makes this easy with it’s out of the box connectors for MS SQL, MySQL and other back ends.
I created a model, SalesByRegion, based on table1 that returned the following data:
{
"success": true,
"request-id": "089bf3ab-8ad4-404d-a2e9-8546485817b2",
"key": "salesbyregions",
"salesbyregions": [
{
"id": 0,
"rid": 0,
"region": "NE",
"act": 66,
"fcst": 77
},
...
{
"id": 3,
"rid": 3,
"region": "Cent",
"act": 52,
"fcst": 61
},
{
"id": 4,
"rid": 4,
"region": "Can",
"act": 35,
"fcst": 71
}
]
}An example of using this API in a mobile application, is shown below.
Now, consider an enhancement, where you would like to display KPI (key performance indicators) in the table indicating the sales performance of each region, using a color scheme as follows:
This small enhancement makes the mobile experience better since it helps the user focus on the areas of interest.
This can easily be implemented in the mobile application in client side code by performing the necessary calculation, say by dividing the actual sales by the forecast and comparing to a threshold to determine what KPI to display. In Titanium, this could be performed in the row controller code as follows:
var p = 100*args.act/args.fcst;
if(p>Alloy.Globals.greenThreshold){
$.kpiImageView.image = '/images/kpi_green.png';
} else if(p<Alloy.Globals.redThreshold){
$.kpiImageView.image = '/images/kpi_red.png';
} else {
$.kpiImageView.image = '/images/kpi_yellow.png';
}However, if the threshold levels were to ever change, a new application would need to be deployed to the users. Let's move this code to the Arrow API instead and return the computed KPI along with the sales data.
###Arrow Model Custom Field
Lets add a custom field, kpi, to the MySQL or MSSQL Arrow Model as follows:
"kpi": {
"type": "string",
"custom": true,
"get": function(val,key,model){
var kpi_val;
var p = 100*model.get('act')/model.get('fcst');
if(p < 50) {
kpi_val="red";
} else if(p < 70) {
kpi_val = "yellow";
} else {
kpi_val = "green";
}
return kpi_val;
}
}Now the data returned by the API looks like this:
{
"success": true,
"request-id": "089bf3ab-8ad4-404d-a2e9-8546485817b2",
"key": "salesbyregions",
"salesbyregions": [
{
"id": 0,
"rid": 0,
"region": "NE",
"act": 66,
"fcst": 77,
"kpi": "green"
},
...
{
"id": 3,
"rid": 3,
"region": "Cent",
"act": 52,
"fcst": 61,
"kpi": "green"
},
{
"id": 4,
"rid": 4,
"region": "Can",
"act": 35,
"fcst": 71,
"kpi": "red"
}
]
}Now the client side code is simply needs to check the kpi value and set the image. No computation is required and threshold values can be modified on the Arrow server without needing to redeploy the mobile app.
###Add a Totals Row
What if you wanted to add a totals row to the table, as follows:
Again, you can easily do this in Titanium by looping through the rows and summing the values for actual and forecast and adding a TableView footer or a ListView footer template to display the totals row.
However, to reduce the computation on the mobile device, we can implement this in the API using an Arrow Block.
We can the following property to the model:
"after": "addtotal",This indicates that after the data is retrieved from the database run the block named addtotal.
addtotal.js is shown below:
var Arrow = require('arrow');
var PostBlock = Arrow.Block.extend({
name: 'addtotal',
description: 'add total row to sales data',
action: function(req, resp, next) {
var body = JSON.parse(resp.body);
var data = body[body.key];
var dataLen = data.length;
var replies = 0;
if(dataLen){ //findAll
var actTotal=0, fcstTotal=0;
data.forEach(function (_row, _index) {
actTotal += _row.act;
fcstTotal += _row.fcst;
});
} else { //findOne
actTotal =data.act;
fcstTotal = data.fcst;
}
resp.success({
data: body[body.key],
totals: {"actTotal": actTotal, "fcstTotal": fcstTotal}
}, next);
}
});
module.exports = PostBlock;The code above will be executed after the data is retreived frome the database, loop through the rows and calculate a totals row, which will be added to the repy object in the resp.success() call.
resp.success({
data: body[body.key],
totals: {"actTotal": actTotal, "fcstTotal": fcstTotal}
}, next);The data that the API now returns is shown below:
{
"success": true,
"request-id": "de51ff25-3778-4696-8c60-58bad9663e23",
"key": "salesbyregion",
"salesbyregion": {
"data": [
{
"id": 0,
"rid": 0,
"region": "NE",
"act": 66,
"fcst": 77,
"kpi": "green"
},
...
{
"id": 3,
"rid": 3,
"region": "Cent",
"act": 52,
"fcst": 61,
"kpi": "green"
},
{
"id": 4,
"rid": 4,
"region": "Can",
"act": 35,
"fcst": 71,
"kpi": "red"
}
],
"totals": {
"actTotal": 220,
"fcstTotal": 298
}
}
}###Summary
In this example, we saw how Arrow can be used to create highly specific and mobile optimized APIs that reduce the computational complexity of the mobile application and reduce the need to deploy new application versions as business rules/logic change.
The code for this example can be found here.



