Name

sn_irm_shared_cmn.IRMGlideUtils

Description

Common utility methods for ServiceNow platform features.

Script

var IRMGlideUtils = Class.create();
IRMGlideUtils.prototype = (function() {
  var TABLES = {
      TABLE_SYS_USER_ROLE: 'sys_user_role',
  };

  /** @type {*} */
  var self;
  /** @type {IRMLogger} */
  var logger;
  var collisionAPI;

  var getCollisionAPI = function() {
      if (typeof collisionAPI === 'undefined') {
          collisionAPI = sn_collision.CollisionAPI;
      }

      return collisionAPI;
  };

  return {
      /**
       * Initialize a new IRMGlideUtils instance.
       * @param {IRMGlideUtilsOptions} options - Options to configure IRMGlideUtils instance.
       * @typedef {Object} IRMGlideUtilsOptions - Options to configure IRMGlideUtils instance.
       * @property {IRMLogger} [logger] - IRM logger instance.
       */
      initialize: function(options) {
          /** @type {*} */
          self = this;
          /** @type {IRMGlideUtilsOptions} */
          var _options = options || {};
          logger = _options.logger || {
              info: gs.info,
              warn: gs.warn,
              error: gs.error,
          };
      },

      /**
       * Check if current user has a specific role(s).
       * @param {string[]} roles - List of role SysIds to check.
       * @returns {boolean} hasRole
       */
      doesUserHaveRole: function(roles) {
          /** @type {*} */
          self = this;
          var _roles = roles instanceof Array ? roles : [roles];
          var roleRecords = self.getGlideRecordData(TABLES.TABLE_SYS_USER_ROLE, {
              filter: 'sys_idIN' + _roles.join(','),
              secure: false,
              select: ['name'],
          });
          var hasRole = false;
          for (var i = 0; i < roleRecords.length; i++) {
              var record = roleRecords[i];
              if (gs.hasRole(record.name)) {
                  hasRole = true;
                  break;
              }
          }

          return hasRole;
      },

      /**
       * Verify if encoded string condition apply on a Glide Record
       * @param {GlideRecord} record - GlideRecord to check against encoded string query.
       * @param {string} condition - Encoded query string to verify.
       * @returns {boolean} isMatch
       */
      doesRecordMatchCondition: function(record, condition) {
          if (gs.nil(condition)) {
              return true;
          }

          /** @type {GlideFilter} */
          var filter = new GlideFilter(condition);
          filter.setCaseSensitive(false);

          return filter.match(record);
      },

      /**
       * A method to retrieve Glide Records by ID.
       * @param {string} table - Table name.
       * @param {string} sysId - SysID for the record.
       * @param {IRMGlideRecordOptions} options - options to configure GlideRecord query.
       * @property {boolean} [secure=true] - Use GlideRecordSecure API.
       * @returns {GlideRecordSecure | GlideRecord} record
       */
      getGlideRecordById: function(table, sysId, options) {
          if (gs.nil(table)) {
              logger.warn('Invalid input for getGlideRecordById. Table value cannot be empty.');

              return null;
          }

          if (gs.nil(sysId)) {
              logger.warn('Invalid input for getGlideRecordById. SysID value cannot be empty.');

              return null;
          }

          var _options = options || {};
          var secure = !gs.nil(_options.secure) ? _options.secure : true;

          /** @type {*} */
          self = this;
          var record = self.getGlideRecord(table, {
              filter: 'sys_id=' + sysId,
              limit: 1,
              secure: secure,
          });

          if (!record.next()) {
              return null;
          }

          return record;
      },

      /**
       * A method to retrieve Glide Records with optional params.
       * This method will also provide log feedback in-case the record was not found.
       * @param {string} table - Table name.
       * @param {IRMGlideRecordOptions} options - options to configure GlideRecord query.
       * @typedef {Object} IRMGlideRecordOptions -  options to configure GlideRecord query.
       * @property {string} [filter] - Encoded query to filter glide record results.
       * @property {number} [limit='sn_irm_shared_cmn.config.get_gliderecord_limit'] - limit the number of returned results.
       * Default to 'sn_irm_shared_cmn.config.get_gliderecord_limit' GlideProperty.
       * @property {string} [orderBy] - Field name to use for sorting the data.
       * @property {boolean} [secure=true] - Use GlideRecordSecure API.
       * @returns {GlideRecordSecure | GlideRecord} record
       */
      getGlideRecord: function(table, options) {
          if (gs.nil(table)) {
              logger.warn('Invalid input for getGlideRecord. Table value cannot be empty.');

              return null;
          }

          /**
           * @constant
           * @type {number}
           */
          var DEFAULT_LIMIT_FALLBACK = 1000;
          var DEFAULT_LIMIT = gs.getProperty('sn_irm_shared_cmn.config.get_gliderecord_limit', DEFAULT_LIMIT_FALLBACK);
          var _options = options || {};
          var filter = _options.filter || null;
          var limit = _options.limit || DEFAULT_LIMIT;
          var secure = !gs.nil(_options.secure) ? _options.secure : true;
          var record = secure ? new GlideRecordSecure(table) : new GlideRecord(table);
          var orderBy = _options.orderBy || record.getDisplayName();
          if (filter) {
              record.addEncodedQuery(filter);
          }

          if (limit && limit > 0) {
              record.setLimit(limit);
          }

          if (orderBy) {
              record.orderBy(orderBy);
          }

          record.query();
          if (!record.hasNext()) {
              logger.warn('Unable to find records for "' + table + '" with filter: ' + filter);
          }

          return record;
      },

      /**
       * A method to retrieve Glide Record data with optional params.
       * This method will also provide log feedback in-case the record was not found.
       * @param {string} table - Table name.
       * @param {IRMRecordDataOptions} options - options to configure returned Record data.
       * @typedef {Object} SelectItem -  options to configure the element to select.
       * @property {string} element - Element (field) name to select.
       * @property {boolean} [display=false] - Specify to retrieve the display value of the element.
       * @typedef {Object} IRMRecordDataOptionsBase -  options to configure returned Record data.
       * @property {string[] | SelectItem[]} [select] - Select GlideRecord fields to return.
       * @typedef {IRMGlideRecordOptions & IRMRecordDataOptionsBase} IRMRecordDataOptions
       * @returns {string[] | object[]} recordData - Return records' SysIds by default,
       * or record values if `select` option is passed.
       */
      getGlideRecordData: function(table, options) {
          if (gs.nil(table)) {
              logger.warn('Invalid input for getGlideRecordData. Table value cannot be empty.');

              return null;
          }

          /** @type {*} */
          self = this;
          var _options = options || {};
          var select = _options.select || null;
          var results = [];
          var record = self.getGlideRecord(table, {
              filter: _options.filter,
              limit: _options.limit,
              orderBy: _options.orderBy,
              secure: _options.secure,
          });
          while (record.next()) {
              if (select && select.length > 0) {
                  /** @type {object} */
                  var recordData = {};
                  // eslint-disable-next-line no-loop-func
                  select.forEach(function(selectItem) {
                      var item = typeof selectItem === 'object' ? selectItem : { element: selectItem };
                      var field = item.element;
                      if (!field) {
                          logger.warn('Invalid field to retrieve for ' + table);

                          return;
                      }

                      var display = item.display;
                      var value = display ? record.getDisplayValue(field) : record.getValue(field);
                      recordData[field] = value;
                  });
                  results.push(recordData);
              } else {
                  results.push(record.getUniqueValue());
              }
          }

          return results;
      },

      /**
       * A method to retrieve the count for Glide Records within a table.
       * @param {string} table - Table name.
       * @param {IRMRecordCountOptions} options - options to configure Record count query.
       * @typedef {Object} IRMRecordCountOptions -  options to configure Record count query.
       * @property {string} [filter] - Encoded query to filter glide record results.
       * @returns {number} count
       */
      getRecordCount: function(table, options) {
          var count = 0;
          var _options = options || {};
          var filter = _options.filter || '';
          var aggregate = new GlideAggregate(table);
          aggregate.addAggregate('COUNT');
          if (filter) {
              aggregate.addEncodedQuery(filter);
          }

          aggregate.query();
          if (!aggregate.next()) {
              logger.info('No record count found for table "' + table + '" with filter: ' + filter);

              return count;
          }

          var aggregateCount = aggregate.getAggregate('COUNT');
          count = isNaN(aggregateCount) ? 0 : Number(aggregateCount);

          return count;
      },

      /**
       * Get mandatory elements for a table.
       * @param {string} table - Table name to get mandatory fields for.
       * @returns {string[]} elements - Elements marked as `Mandatory`.
       */
      getMandatoryElements: function(table) {
          var elements = [];
          if (gs.nil(table)) {
              logger.warn('Invalid input for getMandatoryElements. Table value cannot be empty.');

              return elements;
          }

          var ga = new GlideAggregate('sys_dictionary');
          ga.addQuery('name', table);
          ga.addQuery('mandatory', '=', 'true');
          ga.groupBy('element');
          ga.query();
          while (ga.next()) {
              elements.push(ga.getValue('element'));
          }

          return elements;
      },

      /**
       * Get table ACL
       * @param {string} table - Table name to get ACL table.
       * * @param {string} sysId - Sys Id to get ACL for record.
       * @returns {Object} output - ACLs.
       */
      getTableACL: function(table, sysId) {
          var output = {
              canRead: false,
              canWrite: false,
              canCreate: false,
              canDelete: false,
          };
          if (!gs.nil(table)) {
              var grObj = new GlideRecord(table);
              if (!gs.nil(sysId)) {
                  grObj.get(sysId);
              }

              output.canRead = grObj.canRead();
              output.canWrite = grObj.canWrite();
              output.canCreate = grObj.canCreate();
              output.canDelete = grObj.canDelete();
          } else {
              logger.warn('Invalid input for getTableACL. Table value cannot be empty.');
          }

          return output;
      },

      /**
       * A method to retrieve record's related list details.
       * @param {String} parentTable - Name of the parent table.
       * @param {String} parentId - sys_id of the parent record.
       * @param {String} relatedListName - Name of the related list to fetch the details.
       * @param {String} view - Name of the view
       * @returns {Object} Object containing related list label, name, and filter.
       */
      getRelatedListDetails: function(parentTable, parentId, relatedListName, view) {
          var self = this;
          var relationshipLabel = '';
          var sysRelationshipId = '';
          var relationshipTable = '';
          var parentRefField = '';
          var prefix = 'REL:';
          var filters = [];
          var output = {
              label: '',
              name: relatedListName,
              filter: '',
          };

          view = view || '';

          if (gs.nil(relatedListName)) {
              logger.warn('Passed parameter relatedListName=' + relatedListName + ', cannot be null or empty.');

              return output;
          }

          var isScripted = relatedListName.startsWith(prefix);
          if (isScripted) {
              sysRelationshipId = relatedListName.substring(prefix.length, relatedListName.length);
          } else {
              var relNameArr = relatedListName.split('.');
              if (relNameArr.length === 2) {
                  relationshipTable = relNameArr[0];
                  parentRefField = relNameArr[1];
              }
          }

          var entryGr = new GlideRecord('sys_ui_related_list_entry');
          entryGr.addQuery('related_list', relatedListName);
          entryGr.addQuery('list_id.view.name', view);
          entryGr.setLimit(1);
          entryGr.query();

          if (entryGr.next()) {
              var filter = entryGr.getValue('filter');
              if (filter) {
                  filters.push(filter);
              }
          }

          if (isScripted) {
              var relationshipGr = new GlideRecord('sys_relationship');
              if (relationshipGr.get(sysRelationshipId)) {
                  relationshipTable = relationshipGr.getValue('basic_query_from');

                  var parentGR = new GlideRecord(parentTable);
                  parentGR.get(parentId);
                  var currentGR = new GlideRecord(relationshipTable);

                  var evaluator = new GlideScopedEvaluator();
                  evaluator.putVariable('parent', parentGR);
                  evaluator.putVariable('current', currentGR);
                  evaluator.evaluateScript(relationshipGr, 'query_with', {});
                  currentGR = evaluator.getVariable('current');

                  filters.push(currentGR.getEncodedQuery());
                  relationshipLabel = relationshipGr.getDisplayValue('name');
              }
          } else if (relationshipTable && parentRefField) {
              var relGr = new GlideRecord(relationshipTable);
              relGr.addQuery(parentRefField, parentId);
              filters.push(relGr.getEncodedQuery());
              relationshipLabel = relGr.getClassDisplayValue();
          }

          output.label = relationshipLabel;
          output.filter = filters.join('^');

          return output;
      },

      /**
       * Check if a GlideRecord is customized.
       * @param {GlideRecord | string} record - GlideRecord to check for customization. (or update name string)
       * @returns {boolean} isCustomized
       */
      isRecordCustomized: function(record) {
          var updateName = record instanceof GlideRecord ? record.getValue('sys_update_name') : record;

          return !getCollisionAPI().willBeReplacedOnUpgrade(updateName);
      },

      /**
       * A method to update a Glide Record by ID.
       * @param {string} table - Table name.
       * @param {string} sysId - SysID for the record.
       * @param {Object} recordData - Key-value pair for fields to update on a record.
       * @typedef {Object} IRMGlideUpdateOutput - Output from IRM GlideRecord update
       * @property {string | null} updated - SysID for the updated record. null if the update fails.
       * @property {boolean} [error] - Indicate if there was an error updating the record.
       * @property {string} [message] - Informational message about the GlideRecord message; normally will contains the reason for update error.
       * @returns {IRMGlideUpdateOutput} updateOutput
       */
      updateGlideRecordById: function(table, sysId, recordData) {
          var output = { updated: null };
          if (gs.nil(table)) {
              logger.warn('Invalid input for updateGlideRecordById. Table value cannot be empty.');
              output.error = true;
              output.message = gs.getMessage('Invalid update. You must specify a valid table to update.');

              return output;
          }

          if (gs.nil(sysId)) {
              logger.warn('Invalid input for updateGlideRecordById. SysID value cannot be empty.');
              output.error = true;
              output.message = gs.getMessage('Invalid update. You must specify a valid record to update.');

              return output;
          }

          /** @type {*} */
          self = this;
          /** @type {GlideRecordSecure | GlideRecord} */
          var record = self.getGlideRecordById(table, sysId);

          if (gs.nil(record)) {
              output.error = true;
              output.message = gs.getMessage('Invalid update. No record found in table {0} with SysID "{1}".', [table, sysId]);

              return null;
          }

          var fields = Object.keys(recordData);
          fields.forEach(function(field) {
              var value = recordData[field];
              record.setValue(field, value);
          });

          output.updated = record.update();
          if (!output.updated) {
              output.error = true;
              output.message = record.getLastErrorMessage();
          }

          return output;
      },

      type: 'IRMGlideUtils',
  };
})();

Sys ID

d1d2d8a7c3852510a6a1f51ca140dda6

Offical Documentation

Official Docs: