Name
global.GlideQueryEvaluator
Description
No description available
Script
function GlideQueryEvaluator() { }
GlideQueryEvaluator.aggregateQueries = {
avg: true,
count: true,
max: true,
min: true,
sum: true,
};
GlideQueryEvaluator.createGlideRecord = function createGlideRecord(glideQuery) {
return glideQuery.plan.some(function (step) { return step.type === 'withAcls'; })
? new GlideRecordSecure(glideQuery.table)
: new GlideRecord(glideQuery.table);
};
GlideQueryEvaluator.getPrimaryKeysFromSchema = function getPrimaryKeysFromSchema(table, schema) {
var primaryKeys = {};
var tableSchema = schema[table];
for (var field in tableSchema) {
if (tableSchema[field].primary) {
primaryKeys[field] = true;
}
}
return primaryKeys;
};
GlideQueryEvaluator.FieldComparisonOperators = {
SAMEAS: true,
NSAMEAS: true,
GT_FIELD: true,
LT_FIELD: true,
GT_OR_EQUALS_FIELD: true,
LT_OR_EQUALS_FIELD: true,
}
GlideQueryEvaluator.getSchemaForPlan = function (table, plan, extraFields) {
var allFields = extraFields ? extraFields.concat() : [];
for (var i = 0; i < plan.length; i++) {
var step = plan[i];
if (step.field) {
allFields.push(step.field);
}
if (GlideQueryEvaluator.FieldComparisonOperators[step.operator]) {
allFields.push(step.value);
}
}
return Schema.of(table, allFields);
};
GlideQueryEvaluator.loadSchemaForTable = function loadSchemaForTable(glideQuery, additionalFields) {
return glideQuery.plan
.filter(function (step) { return step.query; })
.map(function (step) { return step.query; })
.map(function (query) { return GlideQueryEvaluator.getSchemaForPlan(query.table || glideQuery.table, query.plan); })
.reduce(function (acc, schema) {
for (var table in schema) {
acc[table] = acc[table] || {};
for (field in schema[table]) {
acc[table][field] = schema[table][field];
}
}
return acc;
}, GlideQueryEvaluator.getSchemaForPlan(glideQuery.table, glideQuery.plan, additionalFields));
}
GlideQueryEvaluator.encodeQuery = function encodeQuery(glideQuery) {
return glideQuery.plan
.filter(function (step) { return step.whereClause || step.type === 'orderBy' || step.type === 'orderByDesc'; })
.map(function (step) {
if (step.query) {
return (step.type === 'orWhere' ? 'NQ' : '') + GlideQueryEvaluator.encodeQuery(step.query);
}
var or = step.type.startsWith('orWhere') ? 'OR' : '';
switch (step.type) {
case 'where':
case 'orWhere':
var value = step.value;
if (JSUtil.instance_of(step.value, 'java.lang.String')) {
value = step.value.replace('^', '^^');
if (step.operator === 'ON') {
value = GlideQueryEvaluator.encodeOnDateFilter(step.value);
}
} else if (step.operator === 'IN' || step.operator === 'NOT IN') {
value = step.value
.filter(function (v) { return v !== null })
.map(function (v) { return v.toString().replace('^', '^^'); });
} else if (step.operator === 'BETWEEN') {
value = step.value
.filter(function (v) { return v !== null })
.map(function (v) { return v.toString().replace('^', '^^'); })
.join('@');
}
return or + step.field + step.operator + value;
case 'whereNull':
case 'orWhereNull':
return or + step.field + 'ISEMPTY';
case 'whereNotNull':
case 'orWhereNotNull':
return or + step.field + 'ISNOTEMPTY';
case 'orderBy':
return or + 'ORDERBY' + step.field;
case 'orderByDesc':
return or + 'ORDERBYDESC' + step.field;
default:
NiceError.raise('Invalid where clause: ' + step.type);
}
return '';
})
.join('^');
};
GlideQueryEvaluator.executePlan = function executePlan(glideQuery, glideRecord, schema) {
var context = {
glideRecord: glideRecord,
schema: schema,
plan: glideQuery.plan,
};
glideQuery.plan.forEach(function (step) {
if (step.action) {
step.action(context);
}
});
var encodedQuery = GlideQueryEvaluator.encodeQuery(glideQuery);
glideRecord.addEncodedQuery(encodedQuery);
};
GlideQueryEvaluator.checkAggregatePlanHasGroupByAndMatchingAggregate = function checkAggregatePlanHasGroupByAndMatchingAggregate(plan, aggregate, field, name) {
var groupByFound = false;
var aggregateAndFieldMatch = false;
plan.forEach(function (step) {
if (step.type === 'groupBy') {
groupByFound = true;
}
if (step.aggregate && step.type === aggregate && step.field === field) {
aggregateAndFieldMatch = true;
}
});
if (!groupByFound) {
NiceError.raise(name + '() requires groupBy when used with aggregate()');
}
if (!aggregateAndFieldMatch) {
NiceError.raise(name + '() called without matching aggregate and field. '
+ "e.g. aggregate('" + aggregate + "', '" + field + "')'");
}
};
GlideQueryEvaluator.checkIfAggregate = function checkIfAggregate(name, plan) {
if (plan.some(function (step) { return step.aggregate; })) {
NiceError.raise(name + ' cannot be used with aggregate()');
}
};
GlideQueryEvaluator.stepTypesIncompatibleWithSimpleAggregates = {
avg: true,
min: true,
max: true,
sum: true,
count: true,
groupBy: true,
having: true,
limit: true,
orderBy: true,
orderByDesc: true,
};
GlideQueryEvaluator.callSimpleAggregate = function callSimpleAggregate(glideQuery, name, field) {
if (!field && name !== 'count') {
NiceError.raise("Aggregate function '" + name + "' expects a field name");
}
var incompatibleSteps = glideQuery.plan.filter(function (step) {
return GlideQueryEvaluator.stepTypesIncompatibleWithSimpleAggregates[step.type];
});
if (incompatibleSteps.length > 0) {
var illegalMethod = incompatibleSteps[0].aggregate ? 'aggregate' : incompatibleSteps[0].type;
NiceError.raise('Terminal function ' + name + '() is incompatible with ' + illegalMethod + '()');
}
var requestedFields = field ? [field] : [];
var schema = GlideQueryEvaluator.loadSchemaForTable(glideQuery, requestedFields);
requestedFields
.concat(Object.keys(GlideQueryEvaluator.getPrimaryKeysFromSchema(glideQuery.table, schema)))
.forEach(function (f) { Schema.checkField(schema, glideQuery.table, f); });
var glideAggregate = new GlideAggregate(glideQuery.table);
GlideQueryEvaluator.executePlan(glideQuery, glideAggregate, schema);
glideAggregate.setGroup(false);
if (name === 'avg' || name === 'sum') {
Schema.checkSumOrAvgHasNumericType(schema, glideQuery.table, field, name);
}
glideAggregate.addAggregate(name, field);
glideAggregate._query();
glideAggregate._next();
var value = glideAggregate.getAggregate(name, field);
if (name === 'count') {
return parseInt(value, 10);
}
var glideType = schema[glideQuery.table][field].type;
return !value
? Optional.empty("Unable to find matching rows for aggregation '"
+ name + "' of field '" + field + "' using query:\n" + glideQuery)
: Optional.of(
Schema.isNumericField(glideType)
? parseFloat(value)
: GlideToJavaScriptMapper.getGlideToJsFn(glideType)(value)
);
};
GlideQueryEvaluator.createQuerySession = function createQuerySession(glideQuery, fields, options) {
var schema = GlideQueryEvaluator.loadSchemaForTable(glideQuery, fields);
var requiredFields = fields.concat(
Object.keys(GlideQueryEvaluator.getPrimaryKeysFromSchema(glideQuery.table, schema))
);
var isAggregate = glideQuery.plan.filter(function (step) {
return GlideQueryEvaluator.aggregateQueries[step.type];
}).length > 0;
var glideRecord = GlideQueryEvaluator.executeSelectQuery(
glideQuery, schema, requiredFields, GQ.merge({ aggregate: isAggregate }, options || {})
);
var groupedFields = glideQuery.plan
.filter(function (step) { return step.type === 'groupBy'; })
.map(function (step) { return step.field; });
if (!isAggregate && groupedFields.length > 0) {
NiceError.raise('groupBy expects a corresponding call to aggregate()');
}
return {
glideRecord: glideRecord,
schema: schema,
fields: isAggregate ? groupedFields : requiredFields,
isAggregate: isAggregate,
};
};
GlideQueryEvaluator.selectOne = function selectOne(glideQuery, fields) {
var session = GlideQueryEvaluator.createQuerySession(glideQuery, fields, { limit: 1 });
if (!session.glideRecord.next()) {
var reason = 'Unable to find a record with the following query:\n' + glideQuery;
return Optional.empty(reason);
}
var nextJsRecord = GlideToJavaScriptMapper.createNextJsFn(glideQuery, session);
return Optional.lazy(nextJsRecord);
};
GlideQueryEvaluator.createStream = function createStream(glideQuery, fields, options) {
var session;
var nextJsRecord;
if (fields.length > 0 && glideQuery.plan.some(function (step) { return step.aggregate; })) {
NiceError.raise('select does not take fields when used with aggregate()');
}
return new Stream(function () {
if (!session) {
session = GlideQueryEvaluator.createQuerySession(glideQuery, fields, options);
nextJsRecord = GlideToJavaScriptMapper.createNextJsFn(glideQuery, session);
}
if (!session.glideRecord._next()) {
return Stream.END;
}
return nextJsRecord();
});
};
GlideQueryEvaluator.executeSelectQuery = function executeSelectQuery(glideQuery, schema, fields, options) {
if (options.aggregate && glideQuery.plan.some(function (step) { return step.type === 'withAcls'; })) {
NiceError.raise('Cannot use aggregate queries with withAcls()');
}
var glideRecord = options.aggregate
? new GlideAggregate(glideQuery.table)
: GlideQueryEvaluator.createGlideRecord(glideQuery);
if (glideRecord instanceof GlideAggregate) {
glideRecord.setGroup(glideQuery.plan.some(function (step) { return step.type === 'groupBy'; }));
}
fields.forEach(function (field) {
Schema.checkField(schema, glideQuery.table, field);
});
GlideQueryEvaluator.executePlan(glideQuery, glideRecord, schema);
if (options.limit) {
glideRecord.setLimit(options.limit);
}
glideRecord._query();
return glideRecord;
};
GlideQueryEvaluator._getRawValue = function _getRawValue(glideQuery, key, schema, fields, primaryKeys) {
if (!glideQuery.table) {
NiceError.raise('Cannot get: no table given');
}
var gr = GlideQueryEvaluator.createGlideRecord(glideQuery);
var queryFields = fields || [];
queryFields.forEach(function (f) {
Schema.checkField(schema, glideQuery.table, f);
});
return gr.get(key)
? GlideToJavaScriptMapper.copyRecord(
GlideToJavaScriptMapper.getRecordCopierFn(
glideQuery.table,
schema,
Object.keys(primaryKeys).concat(queryFields),
gr
)
)
: undefined;
};
GlideQueryEvaluator.get = function get(glideQuery, key, fields) {
var schema = Schema.of(glideQuery.table, fields || []);
var pks = GlideQueryEvaluator.getPrimaryKeysFromSchema(glideQuery.table, schema);
var value = GlideQueryEvaluator._getRawValue(glideQuery, key, schema, fields, pks);
return value === undefined
? Optional.empty("Unable to find a record in table '" + glideQuery.table + "' with key '" + key + "'")
: Optional.of(value);
};
GlideQueryEvaluator.insert = function insert(glideQuery, changes, selectFields, prefetchedSchema) {
if (!changes) {
NiceError.raise('insert expects an Object to insert');
}
var queryFields = Object.keys(changes);
var fields = queryFields.concat(selectFields);
GlideQueryEvaluator.checkFieldsHaveNoFlag(queryFields, 'insert');
var schema = prefetchedSchema || GlideQueryEvaluator.loadSchemaForTable(glideQuery, fields);
selectFields.forEach(function (f) {
Schema.checkField(schema, glideQuery.table, f);
});
var primaryKeys = GlideQueryEvaluator.getPrimaryKeysFromSchema(glideQuery.table, schema);
var gr = GlideQueryEvaluator.createGlideRecord(glideQuery);
GlideQueryEvaluator.setAllValuesToGlideRecord(schema, glideQuery.table, changes, gr);
GlideQueryEvaluator.executePlan(glideQuery, gr, schema);
var id = gr.insert();
if (!id) {
GlideQueryEvaluator.reportFailure('Failure to insert object', glideQuery.table, gr, changes);
}
return Optional.lazy(function () {
return GlideQueryEvaluator._getRawValue(glideQuery, id, schema, fields, primaryKeys);
});
};
GlideQueryEvaluator.checkFieldsHaveNoFlag = function (fields, name) {
fields.forEach(function (f) {
if (f.contains('$')) {
NiceError.raise('Cannot use field flags when calling ' + name);
}
});
};
GlideQueryEvaluator.update = function update(glideQuery, changes, selectFields,
reason, prefetchedSchema, insertWhenNotFound) {
var plan = glideQuery.plan;
var fieldsToChange = Object.keys(changes);
var fields = fieldsToChange.concat(selectFields);
GlideQueryEvaluator.checkFieldsHaveNoFlag(fieldsToChange, 'update');
var schema = prefetchedSchema || GlideQueryEvaluator.loadSchemaForTable(glideQuery, fields);
var primaryKeys = GlideQueryEvaluator.getPrimaryKeysFromSchema(glideQuery.table, schema);
GlideQueryEvaluator.checkForPrimaryKeyWhere('update', primaryKeys, plan);
var gr = GlideQueryEvaluator.createGlideRecord(glideQuery);
GlideQueryEvaluator.executePlan(glideQuery, gr, schema);
gr.setLimit(1);
gr._query();
if (!gr._next()) {
if (insertWhenNotFound) {
return GlideQueryEvaluator.insert(glideQuery, changes, selectFields, prefetchedSchema);
}
NiceError.raise('Cannot update: unable to find record');
}
GlideQueryEvaluator.setAllValuesToGlideRecord(schema, glideQuery.table, changes, gr);
var id = gr.update(reason);
if (!id) {
GlideQueryEvaluator.reportFailure('Failure to update table', glideQuery.table, gr, changes);
}
return Optional.lazy(function () {
return GlideQueryEvaluator._getRawValue(glideQuery, id, schema, fields, primaryKeys);
});
};
GlideQueryEvaluator.reportFailure = function reportFailure(message, table, glideRecord, changes) {
var errorObj = {
message: message,
table: table,
lastGlideError: glideRecord.getLastErrorMessage(),
changes: changes,
};
NiceError.raise(JSON.stringify(errorObj, null, 2));
};
GlideQueryEvaluator.insertOrUpdate = function insertOrUpdate(glideQuery, changes, selectFields, reason) {
var schema = GlideQueryEvaluator.loadSchemaForTable(glideQuery, Object.keys(changes));
var primaryKeys = GlideQueryEvaluator.getPrimaryKeysFromSchema(glideQuery.table, schema);
var whereSteps = [];
for (var pk in primaryKeys) {
if (!changes[pk]) {
return GlideQueryEvaluator.insert(glideQuery, changes, selectFields, schema);
}
whereSteps.push({
type: 'where',
field: pk,
operator: '=',
value: changes[pk],
whereClause: true,
action: GlideQueryActions.where(glideQuery.table, pk, '=', changes[pk]),
});
}
var query = new GlideQuery(glideQuery.table, glideQuery.plan.concat(whereSteps));
return GlideQueryEvaluator.update(query, changes, selectFields, reason, schema, true);
};
GlideQueryEvaluator.updateMultiple = function updateMultiple(glideQuery, changes) {
var fields = Object.keys(changes);
GlideQueryEvaluator.checkFieldsHaveNoFlag(fields, 'updateMultiple');
var schema = GlideQueryEvaluator.loadSchemaForTable(glideQuery, fields);
var glideRecord = GlideQueryEvaluator.createGlideRecord(glideQuery);
GlideQueryEvaluator.executePlan(glideQuery, glideRecord, schema);
GlideQueryEvaluator.setAllValuesToGlideRecord(schema, glideQuery.table, changes, glideRecord);
glideRecord.updateMultiple();
return {
rowCount: glideRecord.getRowCount(),
};
};
GlideQueryEvaluator.del = function del(glideQuery) {
var schema = GlideQueryEvaluator.loadSchemaForTable(glideQuery);
var glideRecord = GlideQueryEvaluator.createGlideRecord(glideQuery);
GlideQueryEvaluator.executePlan(glideQuery, glideRecord, schema);
glideRecord.deleteMultiple();
};
GlideQueryEvaluator.setSingleValueToGlideRecord = function setSingleValueToGlideRecord(schema, table, field, value, glideRecord) {
Schema.checkField(schema, table, field);
Schema.checkFieldType(schema, table, field, value);
Schema.checkChoice(schema, table, field, value);
var glideType = schema[table][field].type;
var glideValue = Schema.javaScriptValueToGlideValue(glideType, value);
if (glideType === 'simple_name_values') {
glideRecord[field] = glideRecord[field] || {};
for (var k in value) {
glideRecord[field][k] = value[k];
}
} else {
glideRecord.setValue(field, glideValue);
}
};
GlideQueryEvaluator.setAllValuesToGlideRecord = function setAllValuesToGlideRecord(schema, table, obj, glideRecord) {
for (var field in obj) {
var value = obj[field];
GlideQueryEvaluator.setSingleValueToGlideRecord(schema, table, field, value, glideRecord);
}
};
GlideQueryEvaluator.checkForPrimaryKeyWhere = function checkForPrimaryKeyWhere(action, primaryKeys, plan) {
var whereSteps = plan.filter(function (step) {
return step.type === 'where';
});
if (whereSteps.length < 1 || whereSteps.some(function (step) {
return !primaryKeys[step.field];
})) {
NiceError.raise(action + " is missing 'where' clause(s) with primary key(s)");
}
};
GlideQueryEvaluator.DATE_FILTERS = {
today: 'javascript:gs.beginningOfToday()@javascript:gs.endOfToday()',
yesterday: 'javascript:gs.beginningOfYesterday()@javascript:gs.endOfYesterday()',
tomorrow: 'javascript:gs.beginningOfTomorrow()@javascript:gs.endOfTomorrow()',
this_week: 'javascript:gs.beginningOfThisWeek()@javascript:gs.endOfThisWeek()',
last_week: 'javascript:gs.beginningOfLastWeek()@javascript:gs.endOfLastWeek()',
next_week: 'javascript:gs.beginningOfNextWeek()@javascript:gs.endOfNextWeek()',
this_month: 'javascript:gs.beginningOfThisMonth()@javascript:gs.endOfThisMonth()',
last_month: 'javascript:gs.beginningOfLastMonth()@javascript:gs.endOfLastMonth()',
next_month: 'javascript:gs.beginningOfNextMonth()@javascript:gs.endOfNextMonth()',
last_3_months: 'javascript:gs.beginningOfLast3Months()@javascript:gs.endOfLast3Months()',
last_6_months: 'javascript:gs.beginningOfLast6Months()@javascript:gs.endOfLast6Months()',
last_9_months: 'javascript:gs.beginningOfLast9Months()@javascript:gs.endOfLast9Months()',
last_12_months: 'javascript:gs.beginningOfLast12Months()@javascript:gs.endOfLast12Months()',
this_quarter: 'javascript:gs.beginningOfThisQuarter()@javascript:gs.endOfThisQuarter()',
last_quarter: 'javascript:gs.beginningOfLastQuarter()@javascript:gs.endOfLastQuarter()',
last_2_quarters: 'javascript:gs.beginningOfLast2Quarters()@javascript:gs.endOfLast2Quarters()',
next_quarter: 'javascript:gs.beginningOfNextQuarter()@javascript:gs.endOfNextQuarter()',
next_2_quarters: 'javascript:gs.beginningOfNext2Quarters()@javascript:gs.endOfNext2Quarters()',
this_year: 'javascript:gs.beginningOfThisYear()@javascript:gs.endOfThisYear()',
next_year: 'javascript:gs.beginningOfNextYear()@javascript:gs.endOfNextYear()',
};
GlideQueryEvaluator.encodeOnDateFilter = function (filter) {
var cannedQuery = GlideQueryEvaluator.DATE_FILTERS[filter];
if (cannedQuery) {
return filter + '@' + cannedQuery;
}
if (filter.split('@').length < 3) {
NiceError.raise("Unable to parse ON operator value '" + filter + "'");
}
return filter;
};
Sys ID
d52b3c8a08013300fa9b4300d8d67a76