Source: Fetch.js

"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