Functional JavaScript - GlideRecord, Part 2: mapGR
After many months seeking enlightment and inspiration for continuing this series of articles, we're finally ready to continue our functional journey!(Or, I'm just a lazy guy who procastinated for far too long... ;-))
In Part 1, we created a simple query helper function that separated GlideRecord query and looping logic from record-level processing logic.
For this article, we'll review some record-level processing logic and as we did before, look for opportunities to factor out repeated, boilerplate code.
Here's some real world code (adapted from HAAPIs script include):
function ex_1() {
var gr = new GlideRecord('sys_cluster_state');
gr.get('status', 'online');
var lastDate = gr.most_recent_message.getGlideObject().getRaw();
var lastDateSecs = (new Packages.java.util.Date().getTime() - lastDate.getTime()) / 1000;
var nodeConfig = {
sys_id: gr.sys_id.toString(),
system_id: gr.system_id.toString(),
status: gr.status.toString(),
last_checkin: gr.most_recent_message.toString(),
last_checkin_friendly: GlideDateUtil.getDateTimeString(lastDateSecs, true)
};
return nodeConfig;
}
We'll cleanup some of the old Legacy API code too, but did you notice some repeated code related to GlideRecord? Yes, the `.toString()` calls on each of the fields being mapped to the nodeConfig object.Alternatively, you may see the `gr.system_id + ''` technique, or perhaps `gr.getValue('system_id')`. If you're not aware, these are all methods to get a string representation of the underlying value encapsulated by the GlideElement object - which is what is returned when you access a GlideRecord property (field).We often need a string value (or non-reference type) to ensure we get a "copy" of the GlideElement value, rather than a reference to the GlideElement itself - which remains constant while looping over a set of GlideRecords, and often results in unexpected behavior.
Wouldn't it be nice if GlideRecord just returned values instead of GlideElement references? Well, that's a topic for another day, but for now, let create a little helper function to do just that.
function mapGR(gr) {
function mapField(obj, field) {
obj[field] = gr[field].toString();
return obj;
}
var fields = Object.keys(gr).sort();
return fields.reduce(mapField, {});
}
Let's clean up and refactor our first example to use the mapGR function:
function ex_2() {
var gr = new GlideRecord('sys_cluster_state');
gr.get('status', 'online');
var node = mapGR(gr);
var lastDate = new GlideDateTime(gr.most_recent_message).getNumericValue();
var lastDateSecs = Math.floor((Date.now() - lastDate) / 1000) + ' seconds';
var nodeConfig = {
sys_id: node.sys_id,
system_id: node.system_id,
status: node.status,
last_checkin: node.most_recent_message,
last_checkin_friendly: lastDateSecs
};
return nodeConfig;
}
Looks a bit cleaner without the `.toString()` cruft in our code, eh?
Next time, we'll enhance the mapGR function to do even more declarative and functional stuff.
Labels:
https://www.servicenow.com/community/developer-articles/functional-javascript-gliderecord-part-2-mapgr/ta-p/2324524
