Show:

File: ..\Scripts\IBlade\a37_dataType.js

/**
  @module breeze
  **/

var DataType = (function () {
  
    /**
    DataType is an 'Enum' containing all of the supported data types.

    @class DataType
    @static
    **/

    /**
    The default value of this DataType.
    @property defaultValue {any}
    **/

    /**
    Whether this is a 'numeric' DataType. 
    @property isNumeric {Boolean}
    **/

    var dataTypeMethods = {
        // default
    };

    var constants = {
        stringPrefix: "K_",
        nextNumber: -1,
        nextNumberIncrement: -1
    };

    var getNextString = function () {
        return constants.stringPrefix + getNextNumber().toString();
    };

    var getNextNumber = function () {
        var result = constants.nextNumber;
        constants.nextNumber += constants.nextNumberIncrement;
        return result;
    };

    var getNextGuid = function () {
        return __getUuid();
    };

    var getNextDateTime = function () {
        return new Date();
    };

    var coerceToString = function (source, sourceTypeName) {
        return (source == null) ? source : source.toString();
    };

    var coerceToInt = function (source, sourceTypeName) {
        if (sourceTypeName === "string") {
            var src = source.trim();
            if (src === "") return null;
            var val = parseInt(src, 10);
            return isNaN(val) ? source : val;
        } else if (sourceTypeName === "number") {
            return Math.round(source);
        }
        // do we want to coerce floats -> ints
        return source;
    };

    var coerceToFloat = function (source, sourceTypeName) {
        if (sourceTypeName === "string") {
            var src = source.trim();
            if (src === "") return null;
            var val = parseFloat(src);
            return isNaN(val) ? source : val;
        }
        return source;
    };

    var coerceToDate = function (source, sourceTypeName) {
        var val;
        if (sourceTypeName === "string") {
            var src = source.trim();
            if (src === "") return null;
            val = new Date(Date.parse(src));
            return __isDate(val) ? val : source;
        } else if (sourceTypeName === "number") {
            val = new Date(source);
            return __isDate(val) ? val : source;
        }
        return source;
    };

    var coerceToBool = function (source, sourceTypeName) {
        if (sourceTypeName === "string") {
            var src = source.trim().toLowerCase();
            if (src === "false" || src ==="") {
                return false;
            } else if (src === "true") {
                return true;
            } else {
                return source;
            }
        } 
        return source;
    };

    var fmtString = function (val) {
        return val == null ? null : "'" + val.replace(/'/g,"''") + "'";
    };

    var fmtInt = function (val) {
        return val == null ? null : ((typeof val === "string") ? parseInt(val, 10) : val);
    };

    var makeFloatFmt = function (fmtSuffix) {
        return function(val) {
            if (val == null) return null;
            if (typeof val === "string") {
                val = parseFloat(val);
            }
            return val + fmtSuffix;
        };
    };

    var fmtDateTime = function (val) {
        if (val == null) return null;
        try {
            return "datetime'" + val.toISOString() + "'";
        } catch (e) {
            throwError("'%1' is not a valid dateTime", val);
        }
    };

    var fmtDateTimeOffset = function (val) {
        if (val == null) return null;
        try {
            return "datetimeoffset'" + val.toISOString() + "'";
        } catch (e) {
            throwError("'%1' is not a valid dateTime", val);
        }
    };

    var fmtTime = function (val) {
        if (val == null) return null;
        if (!__isDuration(val)) {
            throwError("'%1' is not a valid ISO 8601 duration", val);
        }
        return "time'" + val + "'";
    };

    var fmtGuid = function (val) {
        if (val == null) return null;
        if (!__isGuid(val)) {
            throwError("'%1' is not a valid guid", val);
        }
        return "guid'" + val + "'";
    };

    var fmtBoolean = function (val) {
        if (val == null) return null;
        if (typeof val === "string") {
            return val.trim().toLowerCase() === "true";
        } else {
            return !!val;
        }
    };
    
    var fmtBinary = function (val) {
        if (val == null) return val;
        return "binary'" + val + "'";
    };

    var fmtUndefined = function (val) {
        return val;
    };

    function throwError(msg, val) {
        msg = __formatString(msg, val);
        throw new Error(msg);
    }
    
    var DataType = new Enum("DataType", dataTypeMethods);
    
    
    /**
    @property String {DataType}
    @final
    @static
    **/
    DataType.String = DataType.addSymbol({
        defaultValue: "",
        parse: coerceToString,
        fmtOData: fmtString,
        getNext: getNextString
    });
    /**
    @property Int64 {DataType}
    @final
    @static
    **/
    DataType.Int64 = DataType.addSymbol({
        defaultValue: 0, isNumeric: true, isInteger: true, quoteJsonOData: true,
        parse: coerceToInt,
        fmtOData: makeFloatFmt("L"),
        getNext: getNextNumber
    });
    /**
    @property Int32 {DataType}
    @final
    @static
    **/
    DataType.Int32 = DataType.addSymbol({
        defaultValue: 0, isNumeric: true, isInteger: true,
        parse: coerceToInt,
        fmtOData: fmtInt,
        getNext: getNextNumber
    });
    /**
    @property Int16 {DataType}
    @final
    @static
    **/
    DataType.Int16 = DataType.addSymbol({
        defaultValue: 0, isNumeric: true, isInteger: true,
        parse: coerceToInt,
        fmtOData: fmtInt,
        getNext: getNextNumber
    });
    /**
    @property Byte {DataType}
    @final
    @static
    **/
    DataType.Byte = DataType.addSymbol({ defaultValue: 0, isNumeric: true, isInteger: true, parse: coerceToInt, fmtOData: fmtInt });
    /**
    @property Decimal {DataType}
    @final
    @static
    **/
    DataType.Decimal = DataType.addSymbol({
        defaultValue: 0, isNumeric: true, quoteJsonOData: true, isFloat: true,
        parse: coerceToFloat,
        fmtOData: makeFloatFmt("m"),
        getNext: getNextNumber
    });
    /**
    @property Double {DataType}
    @final
    @static
    **/
    DataType.Double = DataType.addSymbol({
        defaultValue: 0, isNumeric: true, isFloat: true,
        parse: coerceToFloat,
        fmtOData: makeFloatFmt("d"),
        getNext: getNextNumber
    });
    /**
    @property Single {DataType}
    @final
    @static
    **/
    DataType.Single = DataType.addSymbol({
        defaultValue: 0, isNumeric: true, isFloat: true,
        parse: coerceToFloat,
        fmtOData: makeFloatFmt("f"),
        getNext: getNextNumber
    });
    /**
    @property DateTime {DataType}
    @final
    @static
    **/
    DataType.DateTime = DataType.addSymbol({
        defaultValue: new Date(1900, 0, 1), isDate: true,
        parse: coerceToDate,
        fmtOData: fmtDateTime,
        getNext: getNextDateTime
    });
    
    /**
    @property DateTimeOffset {DataType}
    @final
    @static
    **/
    DataType.DateTimeOffset = DataType.addSymbol({
        defaultValue: new Date(1900, 0, 1), isDate: true,
        parse: coerceToDate,
        fmtOData: fmtDateTimeOffset,
        getNext: getNextDateTime
    });
    /**
    @property Time {DataType}
    @final
    @static
    **/
    DataType.Time = DataType.addSymbol({ defaultValue: "PT0S", fmtOData: fmtTime });
    /**
    @property Boolean {DataType}
    @final
    @static
    **/
    DataType.Boolean = DataType.addSymbol({ defaultValue: false, parse: coerceToBool, fmtOData: fmtBoolean });
    /**
    @property Guid {DataType}
    @final
    @static
    **/
    DataType.Guid = DataType.addSymbol({
        defaultValue: "00000000-0000-0000-0000-000000000000",
        fmtOData: fmtGuid,
        getNext: getNextGuid
    });
  
    /**
    @property Binary {DataType}
    @final
    @static
    **/
    DataType.Binary = DataType.addSymbol({ defaultValue: null, fmtOData: fmtBinary });
    /**
    @property Undefined {DataType}
    @final
    @static
    **/
    DataType.Undefined = DataType.addSymbol({ defaultValue: undefined , fmtOData: fmtUndefined});
    DataType.seal();

    /**
    Returns the DataType for a specified EDM type name.
    @method fromEdmDataType
    @static
    @param typeName {String}
    @return {DataType} A DataType.
    **/
    DataType.fromEdmDataType = function (typeName) {
        var dt = null;
        var parts = typeName.split(".");
        if (parts.length > 1) {
            var simpleName = parts[1];
            if (simpleName === "image") {
                // hack
                dt = DataType.Byte;
            } else if (parts.length === 2) {
                dt = DataType.fromName(simpleName) || DataType.Undefined;
            } else {
                // enum
                // dt = DataType.Int32;
                dt = DataType.String;
            }
        }

        return dt;
    };

    DataType.fromValue = function(val) {
        if (__isDate(val)) return DataType.DateTime;
        switch (typeof val) {
            case "string":
                if (__isGuid(val)) return DataType.Guid;
                // the >3 below is a hack to insure that if we are inferring datatypes that 
                // very short strings that are valid but unlikely ISO encoded Time's are treated as strings instead.
                else if (__isDuration(val) && val.length > 3) return DataType.Time;
                return DataType.String;
            case "boolean":
                return DataType.Boolean;
            case "number":
                return DataType.Int32;
        }
        return DataType.Undefined;
    };
   
    var _localTimeRegex = /.\d{3}$/;

    DataType.parseTimeFromServer = function (source) {
        if (typeof source === 'string') {
            return source;
        }
        // ODATA v3 format
        if (source && source.__edmType === 'Edm.Time') {
            var seconds = Math.floor(source.ms / 1000);
            return 'PT' + seconds + 'S';
        }
        return source;
    }

    DataType.parseDateAsUTC = function (source) {
        if (typeof source === 'string') {
            // convert to UTC string if no time zone specifier.
            var isLocalTime = _localTimeRegex.test(source);
            source = isLocalTime ? source + 'Z' : source;
        }
        source = new Date(Date.parse(source));
        return source;
    };

    // NOT YET NEEDED --------------------------------------------------
    // var _utcOffsetMs = (new Date()).getTimezoneOffset() * 60000;
    
    //DataType.parseDateAsLocal = function (source) {
    //    var dt = DataType.parseDatesAsUTC(source);
    //    if (__isDate(dt)) {
    //        dt = new Date(dt.getTime() + _utcOffsetMs);
    //    }
    //    return dt;
    //};
    // -----------------------------------------------------------------

    DataType.parseDateFromServer = DataType.parseDateAsUTC;

    DataType.parseRawValue = function(val, dataType) {
        // undefined values will be the default for most unmapped properties EXCEPT when they are set
        // in a jsonResultsAdapter ( an unusual use case).
        if (val === undefined) return undefined;
        if (dataType.isDate && val) {
            if (!__isDate(val)) {
                val = DataType.parseDateFromServer(val);
            }
        } else if (dataType === DataType.Binary) {
            if (val && val.$value !== undefined) {
                val = val.$value; // this will be a byte[] encoded as a string
            }
        } else if (dataType === DataType.Time) {
            val = DataType.parseTimeFromServer(val);
        }
        return val;
    }

    DataType.constants = constants;

    DataType.getSymbols().forEach(function (sym) {
        sym.validatorCtor = getValidatorCtor(sym);
    });

    function getValidatorCtor(symbol) {
        switch (symbol) {
            case DataType.String:
                return Validator.string;
            case DataType.Int64:
                return Validator.int64;
            case DataType.Int32:
                return Validator.int32;
            case DataType.Int16:
                return Validator.int16;
            case DataType.Decimal:
                return Validator.number;
            case DataType.Double:
                return Validator.number;
            case DataType.Single:
                return Validator.number;
            case DataType.DateTime:
                return Validator.date;
            case DataType.DateTimeOffset:
                return Validator.date;
            case DataType.Boolean:
                return Validator.bool;
            case DataType.Guid:
                return Validator.guid;
            case DataType.Byte:
                return Validator.byte;
            case DataType.Binary:
                // TODO: don't quite know how to validate this yet.
                return Validator.none;
            case DataType.Time:
                return Validator.duration;
            case DataType.Undefined:
                return Validator.none;
        }
    }

    return DataType;

})();

breeze.DataType = DataType;