Forked from thisnameissoclever/EXAMPLE - Querying Incident table from client-side script.js
Created
October 17, 2022 19:32
-
-
Save rverrips/753736a57911b1cd8d4574ad3443567e to your computer and use it in GitHub Desktop.
ServiceNow EfficientGlideRecord: A MUCH more efficient and performant client-side GlideRecord queries, as efficient as GlideAjax (or more!)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Client-side | |
doThing(); | |
function doThing() { | |
let eGR = new EfficientGlideRecord('incident') | |
.setLimit(10) | |
.addNotNullQuery('assignment_group') | |
.addField('number') | |
.addField('short_description') | |
.addField('assignment_group', true) //Get display value as well | |
.orderBy('number') | |
.query(function (eGR) { | |
while (eGR.next()) { | |
console.log( | |
'Short description value: ' + eGR.getValue('short_description') + '\n' + | |
'Number: ' + eGR.getValue('number') + '\n' + | |
'Assignment group: ' + eGR.getValue('assignment_group') + ' (' + | |
eGR.getDisplayValue('assignment_group') + ')' | |
); | |
} | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var ClientGlideRecordAJAX = Class.create(); | |
ClientGlideRecordAJAX.prototype = Object.extendsObject(AbstractAjaxProcessor, { | |
gr_config : {}, | |
getPseudoGlideRecord : function() { | |
var grQuery; | |
var responseObj = { | |
'_records' : [], | |
'_row_count' : 0, | |
'_config' : {}, | |
'_executing_as' : { | |
'user_name' : gs.getUserName(), | |
'user_id' : gs.getUserID() | |
} | |
}; | |
this.gr_config = {}; | |
this.gr_config.table_to_query = this.getParameter('table_to_query'); | |
//@type {{get_display_value: boolean, name: string}} | |
this.gr_config.fields_to_get = this.getParameter('fields_to_get'); | |
this.gr_config.record_limit = this.getParameter('record_limit'); | |
this.gr_config.order_by_field = this.getParameter('order_by_field'); | |
this.gr_config.order_by_desc_field = this.getParameter('order_by_desc_field'); | |
this.gr_config.encoded_queries = this.getParameter('encoded_queries'); | |
this.gr_config.queries = this.getParameter('queries'); | |
//Parse queries/encoded queries array and fields_to_get object | |
if (this.gr_config.hasOwnProperty('queries') && this.gr_config.queries) { | |
this.gr_config.queries = JSON.parse(this.gr_config.queries); | |
} | |
if (this.gr_config.hasOwnProperty('fields_to_get') && this.gr_config.fields_to_get) { | |
this.gr_config.fields_to_get = JSON.parse(this.gr_config.fields_to_get); | |
} | |
if (this.gr_config.hasOwnProperty('encoded_queries') && this.gr_config.encoded_queries) { | |
this.gr_config.encoded_queries = JSON.parse(this.gr_config.encoded_queries); | |
} | |
gs.info('EfficientGlideRecord config: \n' + JSON.stringify(this.gr_config, null, 2)); | |
if (!this._validateMandatoryConfig()) { | |
throw new Error( | |
'Mandatory value not specified. ' + | |
'Cannot perform query. Halting.\n' + | |
'Config: \n' + | |
JSON.stringify(this.gr_config) | |
); | |
} | |
grQuery = this._constructAndGetGlideRecord(); | |
grQuery.query(); | |
while (grQuery.next()) { | |
responseObj._records.push( | |
this._getRequestedRecordData(grQuery, this.gr_config) | |
); | |
} | |
responseObj._row_count = responseObj._records.length; | |
responseObj._config = this.gr_config; | |
return JSON.stringify(responseObj); | |
}, | |
_constructAndGetGlideRecord : function() { | |
var i, queryField, queryOperator, queryValue; | |
var grQuery = new GlideRecordSecure(this.gr_config.table_to_query); | |
//Add limit, if specified | |
if ( | |
this.gr_config.hasOwnProperty('record_limit') && | |
this.gr_config.record_limit >= 1 | |
) { | |
grQuery.setLimit(this.gr_config.record_limit); | |
} | |
//add order_by or order_by_desc field, if specified | |
if ( | |
this.gr_config.hasOwnProperty('order_by_desc_field') && | |
this.gr_config.order_by_desc_field | |
) { | |
grQuery.orderByDesc(this.gr_config.order_by_desc_field); | |
} | |
if ( | |
this.gr_config.hasOwnProperty('order_by_field') && | |
this.gr_config.order_by_field | |
) { | |
grQuery.orderBy(this.gr_config.order_by_field); | |
} | |
//Add encoded query, if specified | |
if ( | |
this.gr_config.hasOwnProperty('encoded_queries') && | |
this.gr_config.encoded_queries | |
) { | |
for (i = 0; i < this.gr_config.encoded_queries.length; i++) { | |
if (this.gr_config.encoded_queries[i]) { | |
grQuery.addEncodedQuery(this.gr_config.encoded_queries[i]); | |
} | |
} | |
} | |
//Add field queries if specified | |
if ( | |
this.gr_config.hasOwnProperty('queries') && | |
this.gr_config.queries.length > 0 | |
) { | |
for (i = 0; i < this.gr_config.queries.length; i++) { | |
queryField = this.gr_config.queries[i].field; | |
queryOperator = this.gr_config.queries[i].operator; | |
queryValue = this.gr_config.queries[i].value; | |
grQuery.addQuery(queryField, queryOperator, queryValue); | |
} | |
} | |
return grQuery; | |
}, | |
_validateMandatoryConfig : function() { | |
var i, currentQuery; | |
//Can add more later if necessary | |
var mandatoryFields = [ | |
'table_to_query', | |
'fields_to_get' | |
]; | |
for (i = 0; i < mandatoryFields.length; i++) { | |
if ( | |
!this.gr_config.hasOwnProperty(mandatoryFields[i]) || | |
!this.gr_config[mandatoryFields[i]] | |
) { | |
return false; | |
} | |
} | |
//If both order_by and order_by_desc are specified, log a warning and ignore order_by_desc. | |
// if ( | |
// ( | |
// this.gr_config.hasOwnProperty('order_by_field') && | |
// this.gr_config.order_by_field | |
// ) && | |
// ( | |
// this.gr_config.hasOwnProperty('order_by_desc_field') && | |
// this.gr_config.order_by_desc_field | |
// ) | |
// ) { | |
// gs.warn( | |
// 'ClientGlideRecordAJAX client-callable Script Include called with ' + | |
// 'both an "order by" and "orderby descending" field. It is only possible to ' + | |
// 'specify one field to sort by, either ascending or descending. \n' + | |
// 'Ignoring the descending field, and ordering by the order_by_field field.' | |
// ); | |
// this.gr_config.order_by_desc_field = ''; | |
// } | |
if ( | |
this.gr_config.hasOwnProperty('queries') && | |
this.gr_config.queries | |
) { | |
for (i = 0; i < this.gr_config.queries.length; i++) { | |
currentQuery = this.gr_config.queries[i]; | |
if ( | |
(!currentQuery.hasOwnProperty('field') || !currentQuery.field) || | |
(!currentQuery.hasOwnProperty('operator') || !currentQuery.operator) || | |
(!currentQuery.hasOwnProperty('value') || !currentQuery.value) | |
) { | |
gs.error( | |
'Malformed query provided to ClientGlideRecordAJAX Script Include:\n' + | |
JSON.stringify(currentQuery) | |
); | |
return false; | |
} | |
} | |
} | |
return true; | |
}, | |
_getRequestedRecordData : function(grRecord, config) { | |
var i, canReadField, fieldName, fieldValue, fieldDisplayValue, getDisplay; | |
var recordData = { | |
'_config' : config, | |
'_table_name' : grRecord.getTableName(), | |
'_field_values' : {} | |
}; | |
for (i = 0; i < recordData._config.fields_to_get.length; i++) { | |
fieldName = recordData._config.fields_to_get[i].name; | |
getDisplay = !!recordData._config.fields_to_get[i].get_display_value; | |
//Gotta get canReadField in this way and use it to see if we can see the field values, | |
// cause otherwise GlideRecordSecure freaks alll the way out. | |
canReadField = (grRecord.isValidField(fieldName) && grRecord[fieldName].canRead()); | |
fieldValue = canReadField ? (grRecord.getValue(fieldName) || '') : ''; | |
fieldDisplayValue = (getDisplay && canReadField && fieldValue) ? | |
(grRecord[fieldName].getDisplayValue() || '') : (''); | |
/*gs.debug( | |
'EfficientGlideRecord\n' + | |
'Using fields to get: ' + JSON.stringify(recordData._config.fields_to_get) + | |
'\nGot current field name "' + fieldName + '". \n' + | |
'Getting display: ' + getDisplay + '\n' + | |
'Field value: ' + fieldValue | |
);*/ | |
//Retrieve value (and display value if requested) | |
recordData._field_values[fieldName] = { | |
'name' : fieldName, | |
'value' : fieldValue, | |
'display_value' : fieldDisplayValue, | |
//If false, may be caused by ACL restriction, or by invalid field | |
'can_read' : canReadField | |
}; | |
} | |
return recordData; | |
}, | |
type : 'ClientGlideRecordAJAX' | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @classdesc https://snprotips.com/ todo: Article link here | |
* @class | |
* @author | |
* Tim Woodruff (https://TimothyWoodruff.com) | |
* SN Pro Tips (https://snprotips.com) | |
* @license | |
* Copyright (c) 2022 Tim Woodruff (https://TimothyWoodruff.com) | |
* & SN Pro Tips (https://snprotips.com). | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in all | |
* copies or substantial portions of the Software. | |
* | |
* Alternative licensing is available upon request. Please contact [email protected] | |
* for more info. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
* | |
* @version 1.0.0 | |
*/ | |
class EfficientGlideRecord { | |
/** | |
* Instantiated with the 'new' keyword (as classes typically are when instantiated), this | |
* will construct a client-side EfficientGlideRecord object. The methods of this class can | |
* then be called to construct a client-side GlideRecord query. EfficientGlideRecord | |
* replicates *most* of the functionality of the client-side GlideRecord object, but | |
* with more and enhanced functionality. | |
* EfficientGlideRecord is FAR preferable to using the out-of-box (OOB) client-side | |
* GlideRecord query (even asynchronously), because GlideRecord returns a massive amount | |
* of unnecessary data, and can be much, much slower. EfficientGlideRecord aims to return | |
* only that data which is necessary and requested from the server, thus providing an | |
* efficient interface to query records asynchronously without all the additional overhead | |
* related to information that you don't need. | |
* | |
* Additional documentation can be found on the SN Pro Tips blog, at https://go.snc.guru/egr | |
* NOTE: For info on performing async queries in onSubmit Client Scripts, see | |
* https://go.snc.guru/onsubmit | |
* | |
* @param {String} tableName - The name of the table on which to execute your GlideRecord query | |
* @returns {EfficientGlideRecord} | |
* @example | |
* var egrIncident = new EfficientGlideRecord('incident'); | |
* egrIncident.addField('number') | |
* .addField('assignment_group', true) | |
* .addField('assigned_to', true); | |
* | |
* egrIncident.get('some_incident_sys_id', function(egrInc) { | |
* g_form.addInfoMessage( | |
* egrInc.getValue('number') + '\'s assignment group is ' + | |
* egrInc.getDisplayValue('assignment_group') + ' (sys_id: ' + | |
* egrInc.getValue('assignment_group') + ')\n' + | |
* 'The assignee is ' + egrInc.getDisplayValue('assigned_to') + ' (sys_id: ' + | |
* egrInc.getValue('assigned_to') + ')' | |
* ); | |
* }); | |
* @constructor | |
*/ | |
constructor(tableName) { | |
if (!tableName) { | |
throw new Error( | |
'EfficientGlideRecord constructor called without a valid tableName ' + | |
'argument. Cannot continue.' | |
); | |
} | |
this._config = { | |
'table_to_query' : tableName, | |
'fields_to_get' : [], | |
'record_limit' : 0, | |
'order_by_field' : '', | |
'order_by_desc_field' : '', | |
'encoded_queries' : [], | |
'queries' : [] | |
}; | |
this._row_count = -1; | |
this._query_complete = false; | |
this._records = []; | |
this._current_record_index = -1; | |
this._current_record = {}; | |
this._gaQuery = new GlideAjax('ClientGlideRecordAJAX'); | |
this._gaQuery.addParam('sysparm_name', 'getPseudoGlideRecord'); | |
return this; //todo: Necessary on constructor method? | |
} | |
/** | |
* Add a field to retrieve from the target record(s). | |
* Any fields not specified by calling this method will not be available on the resulting | |
* EfficientGlideRecord object in the callback function after calling .query(). In this | |
* case, a warning will be shown in the console, and .getValue('field_name') will return | |
* a blank string. | |
* If a second argument (getDisplayValue) is not specified and set to true, then the | |
* field's display value will not be available on the resulting EfficientGlideRecord | |
* object in the callback function. In this case, .getDisplayValue('field_name') will | |
* return a blank string. | |
* @param {String} fieldName - The name of the field to retrieve from the server for the | |
* specified record(s). | |
* @param {Boolean} [getDisplayValue=false] - Set this argument to true in order to | |
* retrieve the display value for the specified field. If this is not set to true then | |
* calling .getDisplayValue('field_name') will cause a warning to be logged to the | |
* console, and a blank string will be returned. | |
* @returns {EfficientGlideRecord} | |
* @example | |
* var egrIncident = new EfficientGlideRecord('incident'); | |
* egrIncident.addField('number') | |
* .addField('assignment_group', true) | |
* .addField('assigned_to', true); | |
* | |
* egrIncident.get('some_incident_sys_id', function(egrInc) { | |
* g_form.addInfoMessage( | |
* egrInc.getValue('number') + '\'s assignment group is ' + | |
* egrInc.getDisplayValue('assignment_group') + ' (sys_id: ' + | |
* egrInc.getValue('assignment_group') + ')\n' + | |
* 'The assignee is ' + egrInc.getDisplayValue('assigned_to') + ' (sys_id: ' + | |
* egrInc.getValue('assigned_to') + ')' | |
* ); | |
* }); | |
*/ | |
addField(fieldName, getDisplayValue) { | |
this._config.fields_to_get.push({ | |
'name' : fieldName, | |
'get_display_value' : (!!getDisplayValue) | |
}); | |
return this; | |
} | |
/** | |
* Add a query to the EfficientGlideRecord object. | |
* By specifying a field name, operator, and value, you can perform all sorts of queries. | |
* If only two arguments are specified, then it's assumed that the first is the field | |
* name and the second is the field value. The operator will automatically be set to "=". | |
* | |
* @param {String} fieldName - The name of the field to perform the query against. | |
* @param {String} [operator="="] - The operator to use for the query. | |
* Valid operators: | |
* Numbers: =, !=, >, >=, <, <= | |
* Strings: =, !=, STARTSWITH, ENDSWITH, CONTAINS, DOES NOT CONTAIN, IN, NOT IN, INSTANCEOF | |
* Note: If only two arguments are specified (fieldValue is not defined), then the second | |
* argument will be treated as the value, and the operator will automatically be set to "=". | |
* @param {String} fieldValue - The value to compare, using the specified operator, against | |
* the specified field. | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling (as seen in the example below). | |
* @example | |
* new EfficientGlideRecord('incident') | |
* .setLimit(10) | |
* .addQuery('assignment_group', '!=', 'some_group_sys_id') | |
* .addQuery('assigned_to', 'some_assignee_sys_id') | |
* .addNotNullQuery('assignment_group') | |
* .addField('number') | |
* .addField('short_description') | |
* .addField('assignment_group', true) //Get display value as well | |
* .orderBy('number') | |
* .query(function (egrIncident) { | |
* while (egrIncident.next()) { | |
* console.log( | |
* 'Short description value: ' + egrIncident.getValue('short_description') + '\n' + | |
* 'Number: ' + egrIncident.getValue('number') + '\n' + | |
* 'Assignment group: ' + egrIncident.getValue('assignment_group') + ' (' + | |
* egrIncident.getDisplayValue('assignment_group') + ')' | |
* ); | |
* } | |
* }); | |
*/ | |
addQuery(fieldName, operator, fieldValue) { | |
if (typeof fieldValue === 'undefined') { | |
fieldValue = operator; | |
operator = '='; | |
} | |
this._config.queries.push({ | |
'field' : fieldName, | |
'operator' : operator, | |
'value' : fieldValue | |
}); | |
return this; | |
} | |
/** | |
* Shorthand for this.addQuery(fieldName, '!=', 'NULL');. | |
* @param {String} fieldName - The name of the field to ensure is not empty on returned | |
* records. | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
* @example | |
* new EfficientGlideRecord('incident') | |
* .setLimit(10) | |
* .addQuery('assignment_group', '!=', 'some_group_sys_id') | |
* .addQuery('assigned_to', 'some_assignee_sys_id') | |
* .addNotNullQuery('assignment_group') | |
* .addField('number') | |
* .addField('short_description') | |
* .addField('assignment_group', true) //Get display value as well | |
* .orderBy('number') | |
* .query(function (egrIncident) { | |
* while (egrIncident.next()) { | |
* console.log( | |
* 'Short description value: ' + egrIncident.getValue('short_description') + '\n' + | |
* 'Number: ' + egrIncident.getValue('number') + '\n' + | |
* 'Assignment group: ' + egrIncident.getValue('assignment_group') + ' (' + | |
* egrIncident.getDisplayValue('assignment_group') + ')' | |
* ); | |
* } | |
* }); | |
*/ | |
addNotNullQuery(fieldName) { | |
this.addQuery(fieldName, '!=', 'NULL'); | |
return this; | |
} | |
/** | |
* Shorthand for .addQuery(fieldName, '=', 'NULL') | |
* @param {String} fieldName - The name of the field to use in your query, getting only | |
* records where this field is empty. | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
*/ | |
addNullQuery(fieldName) { | |
this.addQuery(fieldName, '=', 'NULL'); | |
return this; | |
} | |
/** | |
* Add an encoded query string to your query. Records matching this encoded query will | |
* be available in your callback function after calling .query(). | |
* @param {String} encodedQueryString - The encoded query string to use in your query. | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
*/ | |
addEncodedQuery(encodedQueryString) { | |
if (!encodedQueryString || typeof encodedQueryString !== 'string') { | |
throw new Error( | |
'Invalid encoded query string specified. Encoded query must be a valid ' + | |
'non-empty string.' | |
); | |
} | |
this._config.encoded_queries.push(encodedQueryString); | |
return this; | |
} | |
/** | |
* Very similar to .addEncodedQuery(), except that it REPLACES any existing encoded | |
* queries on the GlideRecord, rather than adding to them. | |
* @param {String} encodedQueryString - The exact encoded query, as a string, to use in | |
* your query. | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
*/ | |
setEncodedQuery(encodedQueryString) { | |
//REPLACE existing encoded queries, rather than add to them like .addEncodedQuery(). | |
this._config.encoded_queries = [encodedQueryString]; | |
return this; | |
} | |
/** | |
* todo: docs | |
* @param orderByField | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
*/ | |
addOrderBy(orderByField) { | |
this.orderBy(orderByField); | |
return this; | |
} | |
/** | |
* todo: docs | |
* @param orderByField | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
*/ | |
orderBy(orderByField) { | |
this._config.order_by_field = orderByField; | |
return this; | |
} | |
/** | |
* todo: docs | |
* @param orderByDescField | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
*/ | |
orderByDesc(orderByDescField) { | |
this._config.order_by_desc_field = orderByDescField; | |
return this; | |
} | |
/** | |
* todo: docs | |
* @param limit | |
* @returns {EfficientGlideRecord} - Returns the instantiated object for optional | |
* chain-calling. | |
*/ | |
setLimit(limit) { | |
if (typeof limit !== 'number' || limit <= 0) { | |
throw new Error( | |
'EfficientGlideRecord.setLimit() method called with an invalid argument. ' + | |
'Limit must be a number greater than zero.' | |
); | |
} | |
this._config.record_limit = limit; | |
return this; | |
} | |
/** | |
* todo: docs | |
* @param sysID | |
* @param callbackFn | |
*/ | |
get(sysID, callbackFn) { | |
this.addQuery('sys_id', sysID); | |
this.setLimit(1); | |
this.query(callbackFn); | |
} | |
/** | |
* Perform the async query constructed by calling methods in this class, and get the | |
* field(s) from the resultant record that were requested by calling | |
* .addField(fieldName, getDisplayValue) | |
* @async | |
* @param {EfficientGlideRecord~query} callbackFn - The callback function that will | |
* be executed when the request is complete. | |
* This callback function will be called with one argument. That argument will be the | |
* instantiated EfficientGlideRecord object containing the details about the records | |
* returned from your query, and the methods in this class for interacting with them as | |
* documented in this class. | |
*/ | |
query(callbackFn) { | |
let paramName; | |
if (!this._readyToSend()) { | |
//Meaningful errors are logged by this._readyToSend(). | |
return false; | |
} | |
for (paramName in this._config) { | |
//Prevent iteration into non-own properties | |
if (!this._config.hasOwnProperty(paramName)) { | |
continue; | |
} | |
let paramVal; | |
if (typeof this._config[paramName] === 'object') { | |
paramVal = JSON.stringify(this._config[paramName]); | |
} else { | |
paramVal = this._config[paramName]; | |
} | |
this._gaQuery.addParam( | |
paramName, | |
paramVal | |
); | |
} | |
this._gaQuery.getXMLAnswer(function (answer, eGR) { | |
answer = JSON.parse(answer); | |
//let answer = response.responseXML.documentElement.getAttribute('answer'); | |
// answer = JSON.parse(answer); //Throws if unparseable -- good. | |
if (!answer.hasOwnProperty('_records')) { | |
throw new Error( | |
'Something went wrong when attempting to get records from the server.\n' + | |
'Response object: \n' + | |
JSON.stringify(answer) | |
); | |
} | |
eGR._query_complete = true; | |
eGR._records = answer._records; | |
eGR._row_count = answer._row_count; | |
eGR._executing_as = answer._executing_as; | |
callbackFn(eGR); | |
}, null, this); | |
} | |
/* The following methods can only be called after the query is performed */ | |
/** | |
* | |
* Can only be called from the callback function passed into .query() after the query | |
* has completed. | |
* @returns {boolean} | |
*/ | |
hasNext() { | |
if (!this._query_complete) { | |
/*throw new Error( | |
'The .hasNext() method of EfficientGlideRecord can only be called from the ' + | |
'callback function after calling .query()' | |
);*/ | |
return false; | |
} | |
return (this._row_count > (this._current_record_index + 1)); | |
} | |
/** | |
* todo: docs | |
* @returns {boolean} | |
*/ | |
next() { | |
if (!this._query_complete) { | |
/*throw new Error( | |
'The .next() method of EfficientGlideRecord can only be called from the ' + | |
'callback function after calling .query()' | |
);*/ | |
return false; | |
} | |
if (!this.hasNext()) { | |
return false; | |
} | |
this._current_record_index++; | |
this._current_record = this._records[this._current_record_index]; | |
return true; | |
} | |
/** | |
* Returns true if the specified field exists and can be read (even if it's blank). | |
* Will return false in the following cases: | |
* -The specified field on the current record cannot be read | |
* -The specified field does not exist in the response object (which may happen if you don't | |
* add the field to your request using .addField()). | |
* -The specified field does not exist in the database | |
* @param {String} fieldName - The name of the field to check whether the user can read or not. | |
* @returns {Boolean} - Returns true if the specified field exists and can be read, or | |
* false otherwise. | |
*/ | |
canRead(fieldName) { | |
if (!this._query_complete) { | |
throw new Error( | |
'The .canRead() method of EfficientGlideRecord can only be called from the ' + | |
'callback function after calling .query(callbackFn)' | |
); | |
} | |
if (!this._current_record._field_values.hasOwnProperty(fieldName)) { | |
console.warn( | |
'There is no field with the name ' + fieldName + ' in the ' + | |
'EfficientGlideRecord object. Did you remember to specify that you want to ' + | |
'get that field in the query using .addField()?' | |
); | |
return false; | |
} | |
if (!this._current_record._field_values[fieldName].hasOwnProperty('can_read')) { | |
console.warn( | |
'The requested field "' + fieldName + '" has no can_read node. ' + | |
'This should not happen. Returning a blank false.' | |
) | |
return false; | |
} | |
return this._current_record._field_values[fieldName].can_read || false; | |
} | |
/** | |
* todo: docs | |
* @param fieldName | |
* @returns {string} | |
*/ | |
getValue(fieldName) { | |
if (!this._query_complete) { | |
throw new Error( | |
'The .getValue() method of EfficientGlideRecord can only be called from the ' + | |
'callback function after calling .query(callbackFn)' | |
); | |
} | |
if (!this._current_record._field_values.hasOwnProperty(fieldName)) { | |
console.warn( | |
'There is no field with the name ' + fieldName + ' in the ' + | |
'EfficientGlideRecord object. Did you remember to specify that you want to ' + | |
'get that field in the query using .addField()?' | |
); | |
return ''; | |
} | |
if (!this._current_record._field_values[fieldName].hasOwnProperty('value')) { | |
console.warn( | |
'The requested field "' + fieldName + '" has no value node. ' + | |
'This should not happen. Returning a blank string.' | |
) | |
return ''; | |
} | |
return this._current_record._field_values[fieldName].value || ''; | |
} | |
/** | |
* todo: docs | |
* @param fieldName | |
* @returns {string|*|string} | |
*/ | |
getDisplayValue(fieldName) { | |
if (!this._query_complete) { | |
throw new Error( | |
'The .getDisplayValue() method of EfficientGlideRecord can only be called from the ' + | |
'callback function after calling .query(callbackFn)' | |
); | |
} | |
if (!this._current_record._field_values.hasOwnProperty(fieldName)) { | |
console.warn( | |
'There is no field with the name ' + fieldName + ' in the ' + | |
'EfficientGlideRecord object. Did you remember to specify that you want to ' + | |
'get that field in the query using .addField()?' | |
); | |
return ''; | |
} | |
if ( | |
!this._current_record._field_values[fieldName].hasOwnProperty('display_value') || | |
!this._current_record._field_values[fieldName].display_value | |
) { | |
console.warn( | |
'There is no display value for the field with the name ' + fieldName + | |
' in the EfficientGlideRecord object. Did you remember to specify that you ' + | |
'want to get that field\'s display value in the query using ' + | |
'.addField(fieldName, true)?' | |
); | |
return ''; | |
} | |
return this._current_record._field_values[fieldName].display_value || ''; | |
} | |
/* Private helper methods below */ | |
_readyToSend() { | |
/* todo: | |
-Validate table name is specified | |
-Validate this._config.fields_to_get is set and contains at least one value | |
*/ | |
if (!this._config.table_to_query) { | |
console.error( | |
'EfficientGlideRecord not ready to query. Table name was not specified in ' + | |
'the constructor\'s initialize argument.' | |
); | |
return false; | |
} | |
if ( | |
!this._config.fields_to_get || | |
this._config.fields_to_get.length < 1 | |
) { | |
console.error( | |
'EfficientGlideRecord not ready to query. No fields were specified to ' + | |
'retrieve. \nPlease specify which fields you want to retrieve from the ' + | |
'GlideRecord object using .addField(fieldName, getDisplayValue). ' + | |
'Afterward, in your callback, you can use .getValue(fieldName). If ' + | |
'you set getDisplayValue to true, you can also use ' + | |
'.getDisplayValue(fieldName).' | |
); | |
return false; | |
} | |
//Warn if queries AND encoded queries are both empty and limit is unspecified | |
// (but don't return false) | |
if ( | |
( | |
!this._config.hasOwnProperty('queries') || | |
this._config.queries.length < 1 | |
) && | |
( | |
!this._config.hasOwnProperty('encoded_queries') || | |
this._config.encoded_queries.length < 1 | |
) && | |
( | |
!this._config.hasOwnProperty('record_limit') || | |
this._config.record_limit < 1 | |
) | |
) { | |
console.warn( | |
'The EfficientGlideRecord query has no query and no record limit ' + | |
'associated with it. This may result in poor performance when querying larger ' + | |
'tables. Please make sure that you need all records in the specified table, ' + | |
'as all records will be returned by this query.' | |
); | |
} | |
//Return true if none of the above validations have failed. | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment