"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var XMLWriter = require("xml-writer"); var Fetch = (function () { /** Default Constructor * @class Fetch * @classdesc Provides properties and methods to create FetchXml queries * @param entityName {string} Optional. Name of the entity which the query is for * @param attr {string|boolean|string[]} Optional. Either a column name, or a list of column names, or a boolean value indicating that all the attribute values want to be retrieved. The default value is null, and means that only the primary attribute will be retrieved. * @param filterConditions {object} Optional. Object that describes conditions in an JSON notation. More Info: {@link Fetch#setFilter} * @example <caption>Create an empty FetchXml</caption> * var fetch = new Fetch(); * console.log(fetch.toString()); // outputs: <fetch><entity></entity></fetch> * @example <caption>Create a Fetch query for the "account"" entity, with 3 attributes and one filter</caption> * var fetch = new Fetch("account",["description","createdon","ownerid"],{name:"acme"}); * @example <caption>Create a Fetch query for the "account"" entity, with all attributes and one filter</caption> * var fetch = new Fetch("account",true,{name:"acme"}); */ function Fetch(entityName, attr, filterConditions) { this.entityName = entityName; this.attributes = []; this.operatorNames = ['eq', 'neq', 'gt', 'ge', 'le', 'lt', 'like', 'not-like', 'in', 'not-in', 'between', 'not-between', 'null', 'not-null']; this.operatorJsonNames = ['$eq', '$neq', '$gt', '$ge', '$le', '$lt', '$like', '$notlLike', '$in', '$notIn', '$between', '$notBetween', "", /*'null'*/ , "" /* 'not-null'*/]; this.NOT_NULL_OPERATOR = "$notNull"; if (this.attributes != undefined) this.setAttributes(attr); if (filterConditions != undefined) this.setFilter(filterConditions); } Fetch.prototype.toString = function () { var xw = new XMLWriter(true); xw.startElement('fetch'); xw.startElement('entity'); if (this.entityName) { xw.writeAttribute('name', this.entityName.toLowerCase()); } this.serializeAttributes(this.attributes, xw); this.serializeConditions(this.filter, xw); xw.endDocument(); return xw.toString(); }; Fetch.prototype.serializeAttributes = function (value, writer) { for (var i = 0; i < value.length; i++) { var attr = value[i].toLowerCase(); if (attr == "*") { writer.startElement("all-attributes"); } else { writer.startElement("attribute"); writer.writeAttribute("name", attr); } writer.endElement(); } }; /** * Sets the filter criteria of the current <i>FetchXml</i> with the specified values. * * The specified value can be eiher a {@link Filter} object or a conditions object. * * A conditions object is a Javascript object where every property represents a condition. * * If the object contains a property, and that property contains a simple value, like an string or a number, that means property equals to value. * * If you need to specify another operator, then you have to use the form: {attribute:{$operator:value}} * * If the value is an array, then the $in operator is used. * * If the value is a null value, then the nulloperator is applied. For example: {name:null} will retrieve all the records where the name is null. * * @method Fetch#setFilter * @param filterCondition {Filter|object} A Filter object or a Conditions specified in JSON notation. * * @see Build queries with FetchXML: {@link https://msdn.microsoft.com/en-us/library/gg328332.aspx} * * @example <caption>When the simple syntax is used {name:value} then the $eq operator is used. The following filter retrieves all records where the attribute <i>name</i> is equals to "myAccount"</caption> * var cond = {name:"myAccount"}; * @example <caption>The following retrieves all records where the attribute <i>name</i> is equals to "myAccount" <b>AND</b> the createdon date is equals to the system date</caption> * var cond = {name:"myAccount", createdon:new Date()} * @example <caption>If you need to specify additional operators, then use a subobject with the operator name. The following retrieves all records where the attribute <i>name</i> begins with "contoso%" and the attribute <i>createdon</i> is bigger than the current date</caption> * var cond = {name:{$like:"contoso%"}, createdon:{$bt:new Date()}} * @example <caption>Currently supported operators:</caption> * $eq, $neq, $gt, $ge, $le, $lt, $like, $notlLike, $in, $notIn, $between, $notBetween * @example <caption>If the value is an array, then the <i>in</i> operator is applied. The wollowing means: where name is one of contoso, acme or cycleworks</caption> * var cond = {name:["contoso", "acme", "cycleworks"]}; * @example <caption>To specify the null operator, use a null value next to the attribute name. The following will retrieve all the records where the name is null.</caption> * var cond = {name:null}; * @example <caption>To specify the Not Null operator, use a the "$notNull" value next to the attribute name. The following will retrieve all the records where the name is Not null.</caption> * var cond = {name:"$notNull"}; */ Fetch.prototype.setFilter = function (filterConditions) { if (filterConditions != null) { if (filterConditions instanceof Filter) { this.filter = filterConditions; } else { this.filter = this.convert(filterConditions); } } }; Fetch.prototype.setAttributes = function (attributes) { if (attributes == null) { this.attributes = []; } else { if (Array.isArray(attributes)) { this.attributes = attributes; } else if (typeof attributes == "string") { this.attributes = [attributes]; } else if (typeof attributes == "boolean") { this.attributes = ["*"]; } } }; Fetch.prototype.serializeValue = function (value) { var strValue = ""; if (value !== null && value !== undefined) { if (value instanceof Date) { var dateValue = value; // TODO: Refactor this awful code var pad2 = function (x) { return String("00" + x).slice(-2); }; strValue = dateValue.getUTCFullYear() + "-" + pad2(dateValue.getUTCMonth()) + "-" + pad2(dateValue.getUTCDate()) + " " + pad2(dateValue.getUTCHours()) + ":" + pad2(dateValue.getUTCMinutes()) + ":" + pad2(dateValue.getUTCSeconds()); } else { strValue = value + ""; } } return strValue; }; Fetch.prototype.serializeConditions = function (filter, writer) { if (filter && filter.conditions && filter.conditions.length > 0) { var filterTypeName = FilterTypes[filter.filterType].toLowerCase(); writer.startElement("filter").writeAttribute("type", filterTypeName); for (var i = 0; i < filter.conditions.length; i++) { var filterCondition = filter.conditions[i]; var operatorName = this.operatorNames[filterCondition.operator]; var attributeName = filterCondition.attribute.toLowerCase(); writer.startElement("condition") .writeAttribute("attribute", attributeName) .writeAttribute("operator", operatorName); if (filterCondition.values && filterCondition.values.length > 0) { if (filterCondition.operator == Operators.In || filterCondition.operator == Operators.NotIn || filterCondition.values.length > 1) { for (var j = 0; j < filterCondition.values.length; j++) { var strValue = this.serializeValue(filterCondition.values[j]); writer.startElement("value").text(strValue).endElement(); } } else { var strValue = this.serializeValue(filterCondition.values[0]); writer.writeAttribute("value", strValue); } } writer.endElement(); // condition; } writer.endElement(); // filter; } }; Fetch.prototype.convert = function (conditionExpression) { var filter = new Filter(); for (var propName in conditionExpression) { var propValue = conditionExpression[propName]; if (propValue == null) { filter.conditions.push(new Condition(propName, Operators.Null)); } else if (propValue == this.NOT_NULL_OPERATOR) { filter.conditions.push(new Condition(propName, Operators.NotNull)); } else if (typeof propValue === 'number' || propValue instanceof Number || typeof propValue === 'string' || propValue instanceof String || typeof propValue === 'boolean' || propValue instanceof Date) { filter.conditions.push(new Condition(propName, Operators.Equal, [propValue])); } else if (Array.isArray(propValue)) { filter.conditions.push(new Condition(propName, Operators.In, propValue)); } else if (typeof propValue === 'object' && !(propValue instanceof Date)) { for (var i = 0; i < this.operatorJsonNames.length; i++) { var operatorName = this.operatorJsonNames[i]; if (operatorName && propValue[operatorName] != undefined) { propValue = propValue[operatorName]; if (Array.isArray(propValue)) { filter.conditions.push(new Condition(propName, i, propValue)); } else { filter.conditions.push(new Condition(propName, i, [propValue])); } break; } } } } return filter; }; return Fetch; }()); exports.Fetch = Fetch; /** * Filter Type Values * @typedef {object} FilterTypes * @property {number} And Indicates that all the values in the conditions must be true * @property {number} Or Indicates that only one of the conditions must be true */ var FilterTypes; (function (FilterTypes) { FilterTypes[FilterTypes["And"] = 0] = "And"; FilterTypes[FilterTypes["Or"] = 1] = "Or"; })(FilterTypes = exports.FilterTypes || (exports.FilterTypes = {})); var Filter = (function () { /** * Default Constructor * @class Filter * @classdesc Describes a Filter in a {@link Fetch} query. */ /** @member Filter#conditions {Condition[]} Contains the conditions of this filter */ /** @member Filter#filterType {FilterTypes} Indicates if the filter is an And or Or filter */ function Filter(conditions, filterType) { this.conditions = conditions; this.filterType = filterType; if (this.conditions == null) this.conditions = new Array(); if (this.filterType == null) this.filterType = FilterTypes.And; } return Filter; }()); exports.Filter = Filter; // https://msdn.microsoft.com/en-us/library/gg309405.aspx var Operators; (function (Operators) { Operators[Operators["Equal"] = 0] = "Equal"; Operators[Operators["NotEqual"] = 1] = "NotEqual"; Operators[Operators["GreaterThan"] = 2] = "GreaterThan"; Operators[Operators["GreaterEqual"] = 3] = "GreaterEqual"; Operators[Operators["LessEqual"] = 4] = "LessEqual"; Operators[Operators["LessThan"] = 5] = "LessThan"; Operators[Operators["Like"] = 6] = "Like"; Operators[Operators["NotLike"] = 7] = "NotLike"; Operators[Operators["In"] = 8] = "In"; Operators[Operators["NotIn"] = 9] = "NotIn"; Operators[Operators["Between"] = 10] = "Between"; Operators[Operators["NotBetween"] = 11] = "NotBetween"; Operators[Operators["Null"] = 12] = "Null"; Operators[Operators["NotNull"] = 13] = "NotNull"; })(Operators = exports.Operators || (exports.Operators = {})); var Condition = (function () { function Condition(attribute, operator, values) { this.attribute = attribute; this.operator = operator; this.values = values; } return Condition; }()); exports.Condition = Condition; //# sourceMappingURL=Fetch.js.map