Name

global.Optional

Description

No description available

Script

/**
* Optional is a class used when returning a single record which
* may not exist. Optionals wrap around a value and allow you to
* interface with the value inside, even if it's empty (`null` or `undefined`).
* It's purpose is primarily:
*
*  1. Help protect from referencing `null`/`undefined` values.
*  2. Allow function chaining of a return value.
*
* Optionals are returned by both GlideQuery and Stream.
* @example
*	var userOptional = new GlideQuery('sys_user')
*		.selectOne('first_name');
*
*	var taskOptional = new GlideQuery('task')
*		.getBy({ priority: 2, description: 'Fix computer' })
*
*	var serviceNowUserOptional = new GlideQuery('sys_user')
*		.where('active', true)
*		.where('company.name', 'ServiceNow')
*		.select()
*		.find();
* @constructor
* @param {any} value Value to be contained by Optional
* @param {Function} [lazyGetFn] Function which returns a value. Used when you want the Optional
 to contain data which may be costly to retrieve (like a query) and may not be necessary.
* @param {string} [reason] Reason given when an empty Optional is unwrapped (e.g. using `get()`)
*/
function Optional(value, lazyGetFn, reason) {
  this._value = value;
  this._lazyGetFn = lazyGetFn;
  this._lazyValueFetched = false;
  this._reason = reason;
}

Optional.prototype._get = function _get() {
  if (this._lazyGetFn && !this._lazyValueFetched) {
  	this._value = this._lazyGetFn();
  	this._lazyValueFetched = true;
  }

  return this._value;
};

/**
* Applies function `fn` and returns a new Optional with the mapped value inside.
* @example
* new GlideQuery('sys_user')
*     .whereNotNull('first_name')
*     .selectOne('first_name')
*     .map(function (user) {
*	       return user.first_name.toUpperCase();
*     });
*
* // "FRED"
* @param {Function} fn Mapping function of type A -> B
* @returns {Optional}
*/
Optional.prototype.map = function map(fn) {
  if (!fn) {
  	NiceError.raise('map expects a mapping function of type A -> B');
  }

  return this.isEmpty()
  	? this
  	: new Optional(fn(this._get()));
};

/**
* Similar to map(fn), however fn must return an Optional.
* flatMap(fn) returns a new Optional which contains the
* results of calling fn and unwrapping the value returned.
* @example
* new GlideQuery('alm_asset')
*     .whereNotNull('owned_by')
*     .selectOne('owned_by')
*     .flatMap(function (asset) {
*         return new GlideQuery('sys_user')
*             .getBy({ sys_id: asset.owned_by }, ['first_name', 'last_name', 'company.name'])
*     })
*     .ifPresent(GQ.jsonDebug);
* @param {Function} fn A mapping function of type A -> Optional<B>
* @returns {Optional}
*/
// eslint-disable-next-line consistent-return
Optional.prototype.flatMap = function flatMap(fn) {
  var errorMessage = 'Optional.flatMap expects a mapping function of type A -> Optional<B>';
  if (!fn) {
  	NiceError.raise(errorMessage);
  }

  if (this.isEmpty()) {
  	return this;
  }

  var nextValue = fn(this._get());
  if (nextValue instanceof Optional) {
  	return new Optional(nextValue)._get();
  }

  NiceError.raise(errorMessage);
};

/**
* Returns the value inside the Optional, and throws
* an Error if the optional is empty (null or undefined).
* @example
* new GlideQuery('sys_user')
*     .selectOne('first_name')
*     .get();
*
* // {
* //     sys_id: "f682abf03710200044e0bfc8bcbe5d38",
* //     first_name: "Bob"
* // }
* @throws {Error} When Optional is empty
* @returns {any} Value within Optional
*/
// eslint-disable-next-line consistent-return
Optional.prototype.get = function get() {
  if (this.isPresent()) {
  	return this._get();
  }

  var additionalInfo = this._reason
  	? ': ' + this._reason
  	: '';
  NiceError.raise('get() called on empty Optional' + additionalInfo);
};

/**
* Returns the value inside the Optional, or
* a default value if Optional is empty.
* @example
* new GlideQuery('sys_user')
*     .get(key, ['first_name'])
*     .orElse({ first_name: 'Bob' })
*
* // returns an object with first_name, regardless
* // of whether the record exists in the table
* @param {any} defaultValue Value returned when Optional is empty
* @returns {any}
*/
Optional.prototype.orElse = function orElse(defaultValue) {
  return this.isPresent()
  	? this._get()
  	: defaultValue;
};

/**
* Returns true if Optional is empty (contains `null` or `undefined`),
* otherwise returns true.
* @example
* new GlideQuery('sys_user')
*     .where('last_name', 'Barker')
*     .selectOne()
*     .isEmpty();
* @returns {boolean}
*/
Optional.prototype.isEmpty = function isEmpty() {
  return !this.isPresent();
};

/**
* Returns true if Optional has a value inside (is not `null` or `undefined`),
* otherwise returns false.
* @example
* new GlideQuery('sys_user')
*     .where('last_name', 'Luddy')
*     .selectOne('first_name')
*     .isPresent();
* @returns {boolean}
*/
Optional.prototype.isPresent = function isPresent() {
  var value = this._get();

  return value !== null && value !== undefined;
};

/**
* Applies function to value within Option if not empty,
* otherwise does nothing.
* @example
* new GlideQuery('sys_user')
*     .where('sys_id', 'f682abf03710200044e0bfc8bcbe5d38')
*     .selectOne('zip')
*     .ifPresent(function (user) {
*	       gs.info('Zip Code: ' + user.zip);
*     });
*
* // Prints zip code if user exists, otherwise does nothing
* @param {Function} fn Function to apply
* @returns {nothing}
*/
Optional.prototype.ifPresent = function ifPresent(fn) {
  if (!fn) {
  	NiceError.raise('ifPresent expects a function');
  }
  if (this.isPresent()) {
  	fn(this._get());
  }
};

/**
* Applies a predicate function (a function which takes a single
* value and returns true or false) to the value inside, and returns
* the same Optional unchanged if the predicate returns true. Otherwise,
* returns an empty Optional.
* @example
* new GlideQuery('sys_user')
*     .getBy({ sys_id: 'f682abf03710200044e0bfc8bcbe5d38' }, ['phone'])
*     .filter(function (user) {
*         return phoneRegex.test(user.phone);
*     });
* @param {Function} predicate
* @returns {Optional}
*/
Optional.prototype.filter = function filter(predicate) {
  if (!predicate) {
  	NiceError.raise('filter expects a predicate function');
  }

  if (this.isEmpty()) {
  	return this;
  }

  return predicate(this._get())
  	? this
  	: Optional.empty();
};

Optional.prototype.toString = function toString() {
  if (this.isEmpty()) {
  	return 'Optional.empty' + (this._reason ? (': ' + this._reason) : '');
  }
  return 'Optional<' + this._get() + '>';
};

/**
* Returns an empty Optional
* @param {string} [reason] Reason to display if get() is called on this empty Optional
* @returns {Optional}
*/
Optional.empty = function empty(reason) {
  return new Optional(null, null, reason);
};

/**
* Returns a new Optional
* @param {any} value A value other than `null` or `undefined`
* @throws {Error} When value is `null` or `undefined`
* @returns {Optional}
*/
Optional.of = function of(value) {
  if (value === null || value === undefined) {
  	NiceError.raise('Optional.of() does not allow undefined or null values. Use Optional.empty() instead.');
  }

  return new Optional(value);
};

/**
* Returns a new Optional, but instead of containing the value,
* it contains a function to get the value (if ever requested). This
* is typically used when you want to delay getting the value because
* it's from a slow source, and may not ever be requested to begin with
* @param {Function} lazyGetFn Function which returns a value
* @returns {Optional}
*/
Optional.lazy = function lazy(lazyGetFn) {
  return new Optional(null, lazyGetFn);
};

Sys ID

15bd3bd973692300bb513198caf6a7cf

Offical Documentation

Official Docs: