logo

NJP

Functional JavaScript - GlideRecord, Part 2: mapGR

Import · Oct 06, 2019 · article

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:

image

View original source

https://www.servicenow.com/community/developer-articles/functional-javascript-gliderecord-part-2-mapgr/ta-p/2324524