http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/odata/json.js ---------------------------------------------------------------------- diff --git a/src/lib/odata/json.js b/src/lib/odata/json.js index 6a6968a..f00b54c 100644 --- a/src/lib/odata/json.js +++ b/src/lib/odata/json.js @@ -37,6 +37,8 @@ var isObject = utils.isObject; //var normalizeURI = utils.normalizeURI; var parseInt10 = utils.parseInt10; var getFormatKind = utils.getFormatKind; +var convertByteArrayToHexString = utils.convertByteArrayToHexString; + var formatDateTimeOffset = oDataUtils.formatDateTimeOffset; var formatDuration = oDataUtils.formatDuration; @@ -54,7 +56,6 @@ var lookupDefaultEntityContainer = oDataUtils.lookupDefaultEntityContainer; var lookupProperty = oDataUtils.lookupProperty; var MAX_DATA_SERVICE_VERSION = oDataUtils.MAX_DATA_SERVICE_VERSION; var maxVersion = oDataUtils.maxVersion; -var XXXparseDateTime = oDataUtils.XXXparseDateTime; var isPrimitiveEdmType = oDataUtils.isPrimitiveEdmType; var isGeographyEdmType = oDataUtils.isGeographyEdmType; @@ -80,81 +81,17 @@ var DELTATYPE_DELETED_LINK = "dl"; var jsonMediaType = "application/json"; var jsonContentType = oDataHandler.contentType(jsonMediaType); +var jsonSerializableMetadata = ["@odata.id", "@odata.type"]; -// The regular expression corresponds to something like this: -// /Date(123+60)/ -// -// This first number is date ticks, the + may be a - and is optional, -// with the second number indicating a timezone offset in minutes. -// -// On the wire, the leading and trailing forward slashes are -// escaped without being required to so the chance of collisions is reduced; -// however, by the time we see the objects, the characters already -// look like regular forward slashes. -var jsonDateRE = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/; - -/** Formats the given minutes into (+/-)hh:mm format. - * @param {Number} minutes - Number of minutes to format. - * @returns {String} The minutes in (+/-)hh:mm format. - */ -function minutesToOffset(minutes) { - - var sign; - if (minutes < 0) { - sign = "-"; - minutes = -minutes; - } else { - sign = "+"; - } - - var hours = Math.floor(minutes / 60); - minutes = minutes - (60 * hours); - - return sign + formatNumberWidth(hours, 2) + ":" + formatNumberWidth(minutes, 2); -} - -/** Parses the JSON Date representation into a Date object. - * @param {String} value - String value. - * @returns {Date} A Date object if the value matches one; falsy otherwise. - */ -function parseJsonDateString(value) { - - var arr = value && jsonDateRE.exec(value); - if (arr) { - // 0 - complete results; 1 - ticks; 2 - sign; 3 - minutes - var result = new Date(parseInt10(arr[1])); - if (arr[2]) { - var mins = parseInt10(arr[3]); - if (arr[2] === "-") { - mins = -mins; - } - // The offset is reversed to get back the UTC date, which is - // what the API will eventually have. - var current = result.getUTCMinutes(); - result.setUTCMinutes(current - mins); - result.__edmType = "Edm.DateTimeOffset"; - result.__offset = minutesToOffset(mins); - } - if (!isNaN(result.valueOf())) { - return result; - } - } - // Allow undefined to be returned. -} -// Some JSON implementations cannot produce the character sequence \/ -// which is needed to format DateTime and DateTimeOffset into the -// JSON string representation defined by the OData protocol. -// See the history of this file for a candidate implementation of -// a 'formatJsonDateString' function. -/** Parses a JSON OData payload. +/** Extend JSON OData payload with metadata * @param handler - This handler. * @param text - Payload text (this parser also handles pre-parsed objects). * @param {Object} context - Object with parsing context. - * @return An object representation of the OData payload.</returns> + * @return An object representation of the OData payload. */ function jsonParser(handler, text, context) { var recognizeDates = defined(context.recognizeDates, handler.recognizeDates); @@ -172,11 +109,11 @@ function jsonParser(handler, text, context) { return json; } else if (payloadFormat === 1) { - return readPayloadMinimal(json, model, recognizeDates); + return addMinimalMetadataToJsonPayload(json, model, recognizeDates); } else if (payloadFormat === 2) { // to do: using the EDM Model to get the type of each property instead of just guessing. - return readPayloadFull(json, model, recognizeDates); + return addFullMetadataToJsonPayload(json, model, recognizeDates); } else { return json; @@ -184,47 +121,156 @@ function jsonParser(handler, text, context) { } -function addType(data, name, value ) { - var fullName = name + '@odata.type'; - if ( data[fullName] === undefined) { - data[fullName] = '#' + value; + + + + + + + + + + + + + + + +// The regular expression corresponds to something like this: +// /Date(123+60)/ +// +// This first number is date ticks, the + may be a - and is optional, +// with the second number indicating a timezone offset in minutes. +// +// On the wire, the leading and trailing forward slashes are +// escaped without being required to so the chance of collisions is reduced; +// however, by the time we see the objects, the characters already +// look like regular forward slashes. +var jsonDateRE = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/; + + +// Some JSON implementations cannot produce the character sequence \/ +// which is needed to format DateTime and DateTimeOffset into the +// JSON string representation defined by the OData protocol. +// See the history of this file for a candidate implementation of +// a 'formatJsonDateString' function. + + +var jsonReplacer = function (_, value) { + /// <summary>JSON replacer function for converting a value to its JSON representation.</summary> + /// <param value type="Object">Value to convert.</param> + /// <returns type="String">JSON representation of the input value.</returns> + /// <remarks> + /// This method is used during JSON serialization and invoked only by the JSON.stringify function. + /// It should never be called directly. + /// </remarks> + + if (value && value.__edmType === "Edm.Time") { + return formatDuration(value); + } else { + return value; + } +}; + +/** Serializes a ODataJs payload structure to the wire format which can be send to the server + * @param handler - This handler. + * @param data - Data to serialize. + * @param {Object} context - Object with serialization context. + * @returns {String} The string representation of data. + */ +function jsonSerializer(handler, data, context) { + + var dataServiceVersion = context.dataServiceVersion || "4.0"; + var cType = context.contentType = context.contentType || jsonContentType; + + if (cType && cType.mediaType === jsonContentType.mediaType) { + context.dataServiceVersion = maxVersion(dataServiceVersion, "4.0"); + var newdata = formatJsonRequestPayload(data); + if (newdata) { + return JSON.stringify(newdata,jsonReplacer); + } } + return undefined; } -function addTypeNoEdm(data, name, value ) { - var fullName = name + '@odata.type'; - if ( data[fullName] === undefined) { - if ( value.substring(0,4)==='Edm.') { - data[fullName] = '#' + value.substring(4); - } else { - data[fullName] = '#' + value; + + +/** Convert OData objects for serialisation in to a new data structure + * @param data - Data to serialize. + * @returns {String} The string representation of data. + */ +function formatJsonRequestPayload(data) { + if (!data) { + return data; + } + + if (isPrimitive(data)) { + return data; + } + + if (isArray(data)) { + var newArrayData = []; + var i, len; + for (i = 0, len = data.length; i < len; i++) { + newArrayData[i] = formatJsonRequestPayload(data[i]); } + return newArrayData; + } + + var newdata = {}; + for (var property in data) { + if (isJsonSerializableProperty(property)) { + newdata[property] = formatJsonRequestPayload(data[property]); + } } + + return newdata; } -function addTypeColNoEdm(data, name, value ) { - var fullName = name + '@odata.type'; +/** Determine form the attribute name if the attribute is a serializable property + * @param attribute + * @returns {boolean} + */ +function isJsonSerializableProperty(attribute) { + if (!attribute) { + return false; + } - if ( data[fullName] === undefined) { - if ( value.substring(0,4)==='Edm.') { - data[fullName] = '#Collection('+value.substring(4)+ ')'; - } else { - data[fullName] = '#Collection('+value+ ')'; + if (attribute.indexOf("@odata.") == -1) { + return true; + } + + var i, len; + for (i = 0, len = jsonSerializableMetadata.length; i < len; i++) { + var name = jsonSerializableMetadata[i]; + if (attribute.indexOf(name) != -1) { + return true; } } + + return false; +} + +/** Creates an object containing information for the json payload. + * @param {String} kind - JSON payload kind + * @param {String} type - Type name of the JSON payload. + * @returns {Object} Object with kind and type fields. + */ +function jsonMakePayloadInfo(kind, type) { + return { kind: kind, type: type || null }; } -/* Adds typeinformation for String, Boolean and numerical EDM-types. - * The type is determined from the odata-json-format-v4.0.doc specification - * @param data - Date which will be extendet - * @param {Boolean} recognizeDates - True if strings formatted as datetime values should be treated as datetime values. False otherwise. - * @returns An object representation of the OData payload. + +/** Add metadata to an JSON payload complex object containing full metadata + * @param {Object} data - Data structure to be extended + * @param {Object} model - Metadata model + * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. */ -function readPayloadFull(data, model, recognizeDates) { +function addFullMetadataToJsonPayload(data, model, recognizeDates) { var type; if (utils.isObject(data)) { for (var key in data) { @@ -232,35 +278,40 @@ function readPayloadFull(data, model, recognizeDates) { if (key.indexOf('@') === -1) { if (utils.isArray(data[key])) { for (var i = 0; i < data[key].length; ++i) { - readPayloadFull(data[key][i], model, recognizeDates); + addFullMetadataToJsonPayload(data[key][i], model, recognizeDates); } } else if (utils.isObject(data[key])) { if (data[key] !== null) { //don't step into geo.. objects - var isGeo = false; type = data[key+'@odata.type']; - if (type && (isGeographyEdmType(type) || isGeometryEdmType(type))) { - // is gemometry type + if (!type) { + //type unknown + addFullMetadataToJsonPayload(data[key], model, recognizeDates); } else { - readPayloadFull(data[key], model, recognizeDates); + type = type.substring(1); + if (isGeographyEdmType(type) || isGeometryEdmType(type)) { + // don't add type info for geo* types + } else { + addFullMetadataToJsonPayload(data[key], model, recognizeDates); + } } } } else { type = data[key + '@odata.type']; // On .Net OData library, some basic EDM type is omitted, e.g. Edm.String, Edm.Int, and etc. - // For the full metadata payload, we need to full fill the @data.type for each property if it is missing. + // For the full metadata payload, we need to full fill the @data.type for each property if it is missing. // We do this is to help the OlingoJS consumers to easily get the type of each property. if (!assigned(type)) { - // Guessing the "type" from the type of the value is not the right way here. - // To do: we need to get the type from metadata instead of guessing. + // Guessing the "type" from the type of the value is not the right way here. + // To do: we need to get the type from metadata instead of guessing. var typeFromObject = typeof data[key]; if (typeFromObject === 'string') { addType(data, key, 'String'); } else if (typeFromObject === 'boolean') { addType(data, key, 'Boolean'); } else if (typeFromObject === 'number') { - if (data[key] % 1 === 0) { // has fraction + if (data[key] % 1 === 0) { // has fraction addType(data, key, 'Int32'); // the biggst integer } else { addType(data, key, 'Decimal'); // the biggst float single,doulbe,decimal @@ -281,96 +332,424 @@ function readPayloadFull(data, model, recognizeDates) { return data; } -/** Serializes the data by returning its string representation. - * @param handler - This handler. - * @param data - Data to serialize. - * @param {Object} context - Object with serialization context. - * @returns {String} The string representation of data. +/** Loop through the properties of an JSON payload object, look up the type info of the property and call + * the appropriate add*MetadataToJsonPayloadObject function + * @param {Object} data - Data structure to be extended + * @param {String} objectInfoType - Information about the data (name,type,typename,...) + * @param {String} baseURI - Base Url + * @param {Object} model - Metadata model + * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. */ -function jsonSerializer(handler, data, context) { +function checkProperties(data, objectInfoType, baseURI, model, recognizeDates) { + for (var name in data) { + if (name.indexOf("@") === -1) { + var curType = objectInfoType; + var propertyValue = data[name]; + var property = lookupProperty(curType.property,name); //TODO SK add check for parent type - var dataServiceVersion = context.dataServiceVersion || "4.0"; - var cType = context.contentType = context.contentType || jsonContentType; + while (( property === null) && (curType.baseType !== undefined)) { + curType = lookupEntityType(curType.baseType, model); + property = lookupProperty(curType.property,name); + } - if (cType && cType.mediaType === jsonContentType.mediaType) { - context.dataServiceVersion = maxVersion(dataServiceVersion, "4.0"); - var newdata = formatJsonRequestPayload(data); - if (newdata) { - return JSON.stringify(newdata); + if ( isArray(propertyValue)) { + //data[name+'@odata.type'] = '#' + property.type; + if (isCollectionType(property.type)) { + addTypeColNoEdm(data,name,property.type.substring(11,property.type.length-1)); + } else { + addTypeNoEdm(data,name,property.type); + } + + + for ( var i = 0; i < propertyValue.length; i++) { + addMetadataToJsonMinimalPayloadComplex(propertyValue[i], property, baseURI, model, recognizeDates); + } + } else if (isObject(propertyValue) && (propertyValue !== null)) { + addMetadataToJsonMinimalPayloadComplex(propertyValue, property, baseURI, model, recognizeDates); + } else { + //data[name+'@odata.type'] = '#' + property.type; + addTypeNoEdm(data,name,property.type); + if (recognizeDates) { + convertDates(data, name, property.type); + } + } } } - - return undefined; } -function formatJsonRequestPayload(data) { - if (!data) { - return data; - } - if (isPrimitive(data)) { - return data; - } - if (isArray(data)) { - var newArrayData = []; - var i, len; - for (i = 0, len = data.length; i < len; i++) { - newArrayData[i] = formatJsonRequestPayload(data[i]); - } +/** Add metadata to an JSON payload object containing minimal metadata + * @param {Object} data - Json response payload object + * @param {Object} model - Object describing an OData conceptual schema + * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. + * @returns {Object} Object in the library's representation. + */ +function addMinimalMetadataToJsonPayload(data, model, recognizeDates) { - return newArrayData; + if (!assigned(model) || isArray(model)) { + return data; } - var newdata = {}; - for (var property in data) { - if (isJsonSerializableProperty(property)) { - newdata[property] = formatJsonRequestPayload(data[property]); + var baseURI = data[contextUrlAnnotation]; + var payloadInfo = createPayloadInfo(data, model); + + switch (payloadInfo.detectedPayloadKind) { + + case PAYLOADTYPE_VALUE: + if (payloadInfo.type !== null) { + return addMetadataToJsonMinimalPayloadEntity(data, payloadInfo, baseURI, model, recognizeDates); + } else { + return addTypeNoEdm(data,'value', payloadInfo.typeName); + } + + case PAYLOADTYPE_FEED: + return addMetadataToJsonMinimalPayloadFeed(data, model, payloadInfo, baseURI, recognizeDates); + + case PAYLOADTYPE_ENTRY: + return addMetadataToJsonMinimalPayloadEntity(data, payloadInfo, baseURI, model, recognizeDates); + + case PAYLOADTYPE_COLLECTION: + return addMetadataToJsonMinimalPayloadCollection(data, model, payloadInfo, baseURI, recognizeDates); + + case PAYLOADTYPE_PROPERTY: + if (payloadInfo.type !== null) { + return addMetadataToJsonMinimalPayloadEntity(data, payloadInfo, baseURI, model, recognizeDates); + } else { + return addTypeNoEdm(data,'value', payloadInfo.typeName); + } + + case PAYLOADTYPE_SVCDOC: + return data; + + case PAYLOADTYPE_LINKS: + return data; + } + + return data; +} + +/** Add metadata to an JSON payload feed object containing minimal metadata + * @param {Object} data - Data structure to be extended + * @param {Object} model - Metadata model + * @param {String} feedInfo - Information about the data (name,type,typename,...) + * @param {String} baseURI - Base Url + * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. + */ +function addMetadataToJsonMinimalPayloadFeed(data, model, feedInfo, baseURI, recognizeDates) { + var entries = []; + var items = data.value; + var i,len; + var entry; + for (i = 0, len = items.length; i < len; i++) { + var item = items[i]; + if ( defined(item['@odata.type'])) { // in case of mixed feeds + var typeName = item['@odata.type'].substring(1); + var type = lookupEntityType( typeName, model); + var entryInfo = { + contentTypeOdata : feedInfo.contentTypeOdata, + detectedPayloadKind : feedInfo.detectedPayloadKind, + name : feedInfo.name, + type : type, + typeName : typeName + }; + + entry = addMetadataToJsonMinimalPayloadEntity(item, entryInfo, baseURI, model, recognizeDates); + } else { + entry = addMetadataToJsonMinimalPayloadEntity(item, feedInfo, baseURI, model, recognizeDates); } + + entries.push(entry); } + data.value = entries; + return data; +} - return newdata; + +/** Add metadata to an JSON payload entity object containing minimal metadata + * @param {Object} data - Data structure to be extended + * @param {String} objectInfo - Information about the data (name,type,typename,...) + * @param {String} baseURI - Base Url + * @param {Object} model - Metadata model + * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. + */ +function addMetadataToJsonMinimalPayloadEntity(data, objectInfo, baseURI, model, recognizeDates) { + addType(data,'',objectInfo.typeName); + + var keyType = objectInfo.type; + while ((defined(keyType)) && ( keyType.key === undefined) && (keyType.baseType !== undefined)) { + keyType = lookupEntityType(keyType.baseType, model); + } + + if (keyType.key !== undefined) { + var lastIdSegment = objectInfo.name + jsonGetEntryKey(data, keyType); + data['@odata.id'] = baseURI.substring(0, baseURI.lastIndexOf("$metadata")) + lastIdSegment; + data['@odata.editLink'] = lastIdSegment; + } + + //var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata")); + + checkProperties(data, objectInfo.type, baseURI, model, recognizeDates); + + return data; } -/** JSON replacer function for converting a value to its JSON representation. - * @param {Object} value - Value to convert.</param> - * @returns {String} JSON representation of the input value. - * This method is used during JSON serialization and invoked only by the JSON.stringify function. - * It should never be called directly. +/** Add metadata to an JSON payload complex object containing minimal metadata + * @param {Object} data - Data structure to be extended + * @param {String} property - Information about the data (name,type,typename,...) + * @param {String} baseURI - Base Url + * @param {Object} model - Metadata model + * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. */ -function jsonReplacer(_, value) { - +function addMetadataToJsonMinimalPayloadComplex(data, property, baseURI, model, recognizeDates) { + var type = property.type; + if (isCollectionType(property.type)) { + type =property.type.substring(11,property.type.length-1); + } - if (value && value.__edmType === "Edm.Time") { - return formatDuration(value); - } else { - return value; + addType(data,'',property.type); + + var propertyType = lookupComplexType(type, model); + if (propertyType === null) { + return; //TODO check what to do if the type is not known e.g. type #GeometryCollection } + + checkProperties(data, propertyType, baseURI, model, recognizeDates); } +/** Add metadata to an JSON payload collection object containing minimal metadata + * @param {Object} data - Data structure to be extended + * @param {Object} model - Metadata model + * @param {String} collectionInfo - Information about the data (name,type,typename,...) + * @param {String} baseURI - Base Url + * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. + */ +function addMetadataToJsonMinimalPayloadCollection(data, model, collectionInfo, baseURI, recognizeDates) { -/** Creates an object containing information for the json payload. - * @param {String} kind - JSON payload kind, one of the PAYLOADTYPE_XXX constant values. - * @param {String} typeName - Type name of the JSON payload. - * @returns {Object} Object with kind and type fields. + addTypeColNoEdm(data,'', collectionInfo.typeName); + + if (collectionInfo.type !== null) { + var entries = []; + + var items = data.value; + var i,len; + var entry; + for (i = 0, len = items.length; i < len; i++) { + var item = items[i]; + if ( defined(item['@odata.type'])) { // in case of mixed collections + var typeName = item['@odata.type'].substring(1); + var type = lookupEntityType( typeName, model); + var entryInfo = { + contentTypeOdata : collectionInfo.contentTypeOdata, + detectedPayloadKind : collectionInfo.detectedPayloadKind, + name : collectionInfo.name, + type : type, + typeName : typeName + }; + + entry = addMetadataToJsonMinimalPayloadEntity(item, entryInfo, baseURI, model, recognizeDates); + } else { + entry = addMetadataToJsonMinimalPayloadEntity(item, collectionInfo, baseURI, model, recognizeDates); + } + + entries.push(entry); + } + data.value = entries; + } + return data; +} + +/** Add an OData type tag to an JSON payload object + * @param {Object} data - Data structure to be extended + * @param {String} name - Name of the property whose type is set + * @param {String} value - Type name */ -function jsonMakePayloadInfo(kind, type) { +function addType(data, name, value ) { + var fullName = name + '@odata.type'; - /// TODO docu - /// <field name="kind" type="String">Kind of the JSON payload. One of the PAYLOADTYPE_XXX constant values.</field> - /// <field name="type" type="String">Data type of the JSON payload.</field> + if ( data[fullName] === undefined) { + data[fullName] = '#' + value; + } +} - return { kind: kind, type: type || null }; +/** Add an OData type tag to an JSON payload object collection (without "Edm." namespace) + * @param {Object} data - Data structure to be extended + * @param {String} name - Name of the property whose type is set + * @param {String} typeName - Type name + */ +function addTypeColNoEdm(data, name, typeName ) { + var fullName = name + '@odata.type'; + + if ( data[fullName] === undefined) { + if ( typeName.substring(0,4)==='Edm.') { + data[fullName] = '#Collection('+typeName.substring(4)+ ')'; + } else { + data[fullName] = '#Collection('+typeName+ ')'; + } + } +} + + +/** Add an OData type tag to an JSON payload object (without "Edm." namespace) + * @param {Object} data - Data structure to be extended + * @param {String} name - Name of the property whose type is set + * @param {String} value - Type name + */ +function addTypeNoEdm(data, name, value ) { + var fullName = name + '@odata.type'; + + if ( data[fullName] === undefined) { + if ( value.substring(0,4)==='Edm.') { + data[fullName] = '#' + value.substring(4); + } else { + data[fullName] = '#' + value; + } + } + return data; +} +/** Convert the date/time format of an property from the JSON payload object (without "Edm." namespace) + * @param {Object} data - Data structure to be extended + * @param propertyName - Name of the property to be changed + * @param type - Type + */ +function convertDates(data, propertyName,type) { + if (type === 'Edm.Date') { + data[propertyName] = oDataUtils.parseDate(data[propertyName], true); + } else if (type === 'Edm.DateTimeOffset') { + data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true); + } else if (type === 'Edm.Duration') { + data[propertyName] = oDataUtils.parseDuration(data[propertyName], true); + } else if (type === 'Edm.Time') { + data[propertyName] = oDataUtils.parseTime(data[propertyName], true); + } +} + +/** Convert the date/time format of an property from the JSON payload object + * @param {Object} data - Data structure to be extended + * @param propertyName - Name of the property to be changed + * @param type - Type + */ +function convertDatesNoEdm(data, propertyName,type) { + if (type === 'Date') { + data[propertyName] = oDataUtils.parseDate(data[propertyName], true); + } else if (type === 'DateTimeOffset') { + data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true); + } else if (type === 'Duration') { + data[propertyName] = oDataUtils.parseDuration(data[propertyName], true); + } else if (type === 'Time') { + data[propertyName] = oDataUtils.parseTime(data[propertyName], true); + } +} + +/** Formats a value according to Uri literal format + * @param value - Value to be formatted. + * @param type - Edm type of the value + * @returns {string} Value after formatting + */ +function formatLiteral(value, type) { + + value = "" + formatRawLiteral(value, type); + value = encodeURIComponent(value.replace("'", "''")); + switch ((type)) { + case "Edm.Binary": + return "X'" + value + "'"; + case "Edm.DateTime": + return "datetime" + "'" + value + "'"; + case "Edm.DateTimeOffset": + return "datetimeoffset" + "'" + value + "'"; + case "Edm.Decimal": + return value + "M"; + case "Edm.Guid": + return "guid" + "'" + value + "'"; + case "Edm.Int64": + return value + "L"; + case "Edm.Float": + return value + "f"; + case "Edm.Double": + return value + "D"; + case "Edm.Geography": + return "geography" + "'" + value + "'"; + case "Edm.Geometry": + return "geometry" + "'" + value + "'"; + case "Edm.Time": + return "time" + "'" + value + "'"; + case "Edm.String": + return "'" + value + "'"; + default: + return value; + } +} + +/** convert raw byteArray to hexString if the property is an binary property + * @param value - Value to be formatted. + * @param type - Edm type of the value + * @returns {string} Value after formatting + */ +function formatRawLiteral(value, type) { + switch (type) { + case "Edm.Binary": + return convertByteArrayToHexString(value); + default: + return value; + } +} + +/** Formats the given minutes into (+/-)hh:mm format. + * @param {Number} minutes - Number of minutes to format. + * @returns {String} The minutes in (+/-)hh:mm format. + */ +function minutesToOffset(minutes) { + + var sign; + if (minutes < 0) { + sign = "-"; + minutes = -minutes; + } else { + sign = "+"; + } + + var hours = Math.floor(minutes / 60); + minutes = minutes - (60 * hours); + + return sign + formatNumberWidth(hours, 2) + ":" + formatNumberWidth(minutes, 2); +} + +/** Parses the JSON Date representation into a Date object. + * @param {String} value - String value. + * @returns {Date} A Date object if the value matches one; falsy otherwise. + */ +function parseJsonDateString(value) { + + var arr = value && jsonDateRE.exec(value); + if (arr) { + // 0 - complete results; 1 - ticks; 2 - sign; 3 - minutes + var result = new Date(parseInt10(arr[1])); + if (arr[2]) { + var mins = parseInt10(arr[3]); + if (arr[2] === "-") { + mins = -mins; + } + + // The offset is reversed to get back the UTC date, which is + // what the API will eventually have. + var current = result.getUTCMinutes(); + result.setUTCMinutes(current - mins); + result.__edmType = "Edm.DateTimeOffset"; + result.__offset = minutesToOffset(mins); + } + if (!isNaN(result.valueOf())) { + return result; + } + } + + // Allow undefined to be returned. } /** Creates an object containing information for the context - * TODO check dou layout - * @returns {Object} Object with type information - * @returns {Object.detectedPayloadKind(optional)} see constants starting with PAYLOADTYPE_ - * @returns {Object.deltaKind(optional)} deltainformation, one of the following valus DELTATYPE_FEED | DELTATYPE_DELETED_ENTRY | DELTATYPE_LINK | DELTATYPE_DELETED_LINK - * @returns {Object.typeName(optional)} name of the type - * @returns {Object.type(optional)} object containing type information for entity- and complex-types ( null if a typeName is a primitive) -*/ + * @param {String} fragments - Uri fragment + * @param {Object} model - Object describing an OData conceptual schema + * @returns {Object} type(optional) object containing type information for entity- and complex-types ( null if a typeName is a primitive) + */ function parseContextUriFragment( fragments, model ) { var ret = {}; @@ -395,14 +774,14 @@ function parseContextUriFragment( fragments, model ) { } else { //TODO check for navigation resource } - } + } ret.type = undefined; ret.typeName = undefined; var fragmentParts = fragments.split("/"); var type; - + for(var i = 0; i < fragmentParts.length; ++i) { var fragment = fragmentParts[i]; if (ret.typeName === undefined) { @@ -414,7 +793,7 @@ function parseContextUriFragment( fragments, model ) { if ( fragment.charAt(index)=='(') { rCount --; } else if ( fragment.charAt(index)==')') { - rCount ++; + rCount ++; } } @@ -422,7 +801,7 @@ function parseContextUriFragment( fragments, model ) { //TODO throw error } - //remove the projected entity from the fragment; TODO decide if we want to store the projected entity + //remove the projected entity from the fragment; TODO decide if we want to store the projected entity var inPharenthesis = fragment.substring(index+2,fragment.length - 1); fragment = fragment.substring(0,index+1); @@ -482,7 +861,7 @@ function parseContextUriFragment( fragments, model ) { continue; } - + //TODO throw ERROR } else { @@ -492,7 +871,7 @@ function parseContextUriFragment( fragments, model ) { ret.detectedPayloadKind = PAYLOADTYPE_ENTRY; // Capter 10.3 and 10.6 continue; - } + } //check for derived types if (fragment.indexOf('.') !== -1) { @@ -518,18 +897,18 @@ function parseContextUriFragment( fragments, model ) { if (property !== null) { //PAYLOADTYPE_COLLECTION ret.typeName = property.type; - - + + if (utils.startsWith(property.type, 'Collection')) { ret.detectedPayloadKind = PAYLOADTYPE_COLLECTION; var tmp12 = property.type.substring(10+1,property.type.length - 1); ret.typeName = tmp12; - ret.type = lookupComplexType(tmp12, model); + ret.type = lookupComplexType(tmp12, model); ret.detectedPayloadKind = PAYLOADTYPE_COLLECTION; } else { - ret.type = lookupComplexType(property.type, model); + ret.type = lookupComplexType(property.type, model); ret.detectedPayloadKind = PAYLOADTYPE_PROPERTY; - } + } ret.name = fragment; // Capter 10.15 @@ -557,6 +936,7 @@ function parseContextUriFragment( fragments, model ) { return ret; } + /** Infers the information describing the JSON payload from its metadata annotation, structure, and data model. * @param {Object} data - Json response payload object. * @param {Object} model - Object describing an OData conceptual schema. @@ -565,10 +945,8 @@ function parseContextUriFragment( fragments, model ) { * the function will report its kind as PAYLOADTYPE_FEED unless the inferFeedAsComplexType flag is set to true. This flag comes from the user request * and allows the user to control how the library behaves with an ambigous JSON payload. * @return Object with kind and type fields. Null if there is no metadata annotation or the payload info cannot be obtained.. -*/ + */ function createPayloadInfo(data, model) { - - var metadataUri = data[contextUrlAnnotation]; if (!metadataUri || typeof metadataUri !== "string") { return null; @@ -582,45 +960,9 @@ function createPayloadInfo(data, model) { var fragment = metadataUri.substring(fragmentStart + 1); return parseContextUriFragment(fragment,model); } - -/** Processe a JSON response payload with metadata-minimal - * @param {Object} data - Json response payload object - * @param {Object} model - Object describing an OData conceptual schema - * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. - * @returns {Object} Object in the library's representation. - */ -function readPayloadMinimal(data, model, recognizeDates) { - - if (!assigned(model) || isArray(model)) { - return data; - } - - var baseURI = data[contextUrlAnnotation]; - var payloadInfo = createPayloadInfo(data, model); - - switch (payloadInfo.detectedPayloadKind) { - case PAYLOADTYPE_VALUE: - return readPayloadMinimalProperty(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_FEED: - return readPayloadMinimalFeed(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_ENTRY: - return readPayloadMinimalEntry(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_COLLECTION: - return readPayloadMinimalCollection(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_PROPERTY: - return readPayloadMinimalProperty(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_SVCDOC: - return data; - case PAYLOADTYPE_LINKS: - return data; - } - - return data; -} - /** Gets the key of an entry. * @param {Object} data - JSON entry. - * + * @param {Object} data - EDM entity model for key loockup. * @returns {string} Entry instance key. */ function jsonGetEntryKey(data, entityModel) { @@ -647,260 +989,11 @@ function jsonGetEntryKey(data, entityModel) { entityInstanceKey += ")"; return entityInstanceKey; } - -function readPayloadMinimalProperty(data, model, collectionInfo, baseURI, recognizeDates) { - if (collectionInfo.type !== null) { - readPayloadMinimalObject(data, collectionInfo, baseURI, model, recognizeDates); - } else { - addTypeNoEdm(data,'value', collectionInfo.typeName); - //data['[email protected]'] = '#'+collectionInfo.typeName; - } - return data; -} - -function readPayloadMinimalCollection(data, model, collectionInfo, baseURI, recognizeDates) { - //data['@odata.type'] = '#Collection('+collectionInfo.typeName + ')'; - addTypeColNoEdm(data,'', collectionInfo.typeName); - - if (collectionInfo.type !== null) { - var entries = []; - - var items = data.value; - for (i = 0, len = items.length; i < len; i++) { - var item = items[i]; - if ( defined(item['@odata.type'])) { // in case of mixed collections - var typeName = item['@odata.type'].substring(1); - var type = lookupEntityType( typeName, model); - var entryInfo = { - contentTypeOdata : collectionInfo.contentTypeOdata, - detectedPayloadKind : collectionInfo.detectedPayloadKind, - name : collectionInfo.name, - type : type, - typeName : typeName - }; - - entry = readPayloadMinimalObject(item, entryInfo, baseURI, model, recognizeDates); - } else { - entry = readPayloadMinimalObject(item, collectionInfo, baseURI, model, recognizeDates); - } - - entries.push(entry); - } - data.value = entries; - } - return data; -} - -function readPayloadMinimalFeed(data, model, feedInfo, baseURI, recognizeDates) { - var entries = []; - var items = data.value; - for (i = 0, len = items.length; i < len; i++) { - var item = items[i]; - if ( defined(item['@odata.type'])) { // in case of mixed feeds - var typeName = item['@odata.type'].substring(1); - var type = lookupEntityType( typeName, model); - var entryInfo = { - contentTypeOdata : feedInfo.contentTypeOdata, - detectedPayloadKind : feedInfo.detectedPayloadKind, - name : feedInfo.name, - type : type, - typeName : typeName - }; - - entry = readPayloadMinimalObject(item, entryInfo, baseURI, model, recognizeDates); - } else { - entry = readPayloadMinimalObject(item, feedInfo, baseURI, model, recognizeDates); - } - - entries.push(entry); - } - data.value = entries; - return data; -} - -function readPayloadMinimalEntry(data, model, entryInfo, baseURI, recognizeDates) { - return readPayloadMinimalObject(data, entryInfo, baseURI, model, recognizeDates); -} - -/** Formats a value according to Uri literal format - * @param value - Value to be formatted. - * @param type - Edm type of the value - * @returns {string} Value after formatting - */ -function formatLiteral(value, type) { - - value = "" + formatRowLiteral(value, type); - value = encodeURIComponent(value.replace("'", "''")); - switch ((type)) { - case "Edm.Binary": - return "X'" + value + "'"; - case "Edm.DateTime": - return "datetime" + "'" + value + "'"; - case "Edm.DateTimeOffset": - return "datetimeoffset" + "'" + value + "'"; - case "Edm.Decimal": - return value + "M"; - case "Edm.Guid": - return "guid" + "'" + value + "'"; - case "Edm.Int64": - return value + "L"; - case "Edm.Float": - return value + "f"; - case "Edm.Double": - return value + "D"; - case "Edm.Geography": - return "geography" + "'" + value + "'"; - case "Edm.Geometry": - return "geometry" + "'" + value + "'"; - case "Edm.Time": - return "time" + "'" + value + "'"; - case "Edm.String": - return "'" + value + "'"; - default: - return value; - } -} - -function formatRowLiteral(value, type) { - switch (type) { - case "Edm.Binary": - return convertByteArrayToHexString(value); - default: - return value; - } -} - -function convertDates(data, propertyName,type) { - if (type === 'Edm.Date') { - data[propertyName] = oDataUtils.parseDate(data[propertyName], true); - } else if (type === 'Edm.DateTimeOffset') { - data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true); - } else if (type === 'Edm.Duration') { - data[propertyName] = oDataUtils.parseDuration(data[propertyName], true); - } else if (type === 'Edm.Time') { - data[propertyName] = oDataUtils.parseTime(data[propertyName], true); - } -} - -function convertDatesNoEdm(data, propertyName,type) { - if (type === 'Date') { - data[propertyName] = oDataUtils.parseDate(data[propertyName], true); - } else if (type === 'DateTimeOffset') { - data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true); - } else if (type === 'Duration') { - data[propertyName] = oDataUtils.parseDuration(data[propertyName], true); - } else if (type === 'Time') { - data[propertyName] = oDataUtils.parseTime(data[propertyName], true); - } -} - -function checkProperties(data, objectInfoType, baseURI, model, recognizeDates) { - for (var name in data) { - if (name.indexOf("@") === -1) { - var curType = objectInfoType; - var propertyValue = data[name]; - var property = lookupProperty(curType.property,name); //TODO SK add check for parent type - - while (( property === null) && (curType.baseType !== undefined)) { - curType = lookupEntityType(curType.baseType, model); - property = lookupProperty(curType.property,name); - } - - if ( isArray(propertyValue)) { - //data[name+'@odata.type'] = '#' + property.type; - if (isCollectionType(property.type)) { - addTypeColNoEdm(data,name,property.type.substring(11,property.type.length-1)); - } else { - addTypeNoEdm(data,name,property.type); - } - - - for ( var i = 0; i < propertyValue.length; i++) { - readPayloadMinimalComplexObject(propertyValue[i], property, baseURI, model, recognizeDates); - } - } else if (isObject(propertyValue) && (propertyValue !== null)) { - readPayloadMinimalComplexObject(propertyValue, property, baseURI, model, recognizeDates); - } else { - //data[name+'@odata.type'] = '#' + property.type; - addTypeNoEdm(data,name,property.type); - if (recognizeDates) { - convertDates(data, name, property.type); - } - } - } - } -} - -function readPayloadMinimalComplexObject(data, property, baseURI, model, recognizeDates) { - var type = property.type; - if (isCollectionType(property.type)) { - type =property.type.substring(11,property.type.length-1); - } - - //data['@odata.type'] = '#'+type; - addType(data,'',property.type); - - - var propertyType = lookupComplexType(type, model); - if (propertyType === null) { - return; //TODO check what to do if the type is not known e.g. type #GeometryCollection - } - - checkProperties(data, propertyType, baseURI, model, recognizeDates); -} - -function readPayloadMinimalObject(data, objectInfo, baseURI, model, recognizeDates) { - //data['@odata.type'] = '#'+objectInfo.typeName; - addType(data,'',objectInfo.typeName); - - var keyType = objectInfo.type; - while ((defined(keyType)) && ( keyType.key === undefined) && (keyType.baseType !== undefined)) { - keyType = lookupEntityType(keyType.baseType, model); - } - - //if ((keyType !== undefined) && (keyType.key !== undefined)) { - if (keyType.key !== undefined) { - var lastIdSegment = objectInfo.name + jsonGetEntryKey(data, keyType); - data['@odata.id'] = baseURI.substring(0, baseURI.lastIndexOf("$metadata")) + lastIdSegment; - data['@odata.editLink'] = lastIdSegment; - } - - var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata")); - //json ComputeUrisIfMissing(data, entryInfo, actualType, serviceURI, dataModel, baseTypeModel); - - checkProperties(data, objectInfo.type, baseURI, model, recognizeDates); - - return data; -} - -var jsonSerializableMetadata = ["@odata.id", "@odata.type"]; - -function isJsonSerializableProperty(property) { - if (!property) { - return false; - } - - if (property.indexOf("@odata.") == -1) { - return true; - } - - var i, len; - for (i = 0, len = jsonSerializableMetadata.length; i < len; i++) { - var name = jsonSerializableMetadata[i]; - if (property.indexOf(name) != -1) { - return true; - } - } - - return false; -} - /** Determines whether a type name is a primitive type in a JSON payload. * @param {String} typeName - Type name to test. * @returns {Boolean} True if the type name an EDM primitive type or an OData spatial type; false otherwise. */ function jsonIsPrimitiveType(typeName) { - return isPrimitiveEdmType(typeName) || isGeographyEdmType(typeName) || isGeometryEdmType(typeName); } @@ -908,8 +1001,6 @@ function jsonIsPrimitiveType(typeName) { var jsonHandler = oDataHandler.handler(jsonParser, jsonSerializer, jsonMediaType, MAX_DATA_SERVICE_VERSION); jsonHandler.recognizeDates = false; - - exports.createPayloadInfo = createPayloadInfo; exports.jsonHandler = jsonHandler; exports.jsonParser = jsonParser;
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/odata/metadata.js ---------------------------------------------------------------------- diff --git a/src/lib/odata/metadata.js b/src/lib/odata/metadata.js index e37161f..9fdcdfd 100644 --- a/src/lib/odata/metadata.js +++ b/src/lib/odata/metadata.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +'use strict'; /** @module odata/metadata */ @@ -363,7 +364,7 @@ var schema = { /** Converts a Pascal-case identifier into a camel-case identifier. * @param {String} text - Text to convert. * @returns {String} Converted text. - * If the text starts with multiple uppercase characters, it is left as-is.</remarks> + * If the text starts with multiple uppercase characters, it is left as-is. */ function scriptCase(text) { @@ -459,7 +460,6 @@ function parseConceptualModelElement(element) { // Currently, only m: for metadata is supported as a prefix in the internal schema table, // un-prefixed element names imply one a CSDL element. var schemaName = null; - var handled = false; if (isEdmNamespace(nsURI) || nsURI === null) { schemaName = ""; } else if (nsURI === odataMetaXmlNs) { @@ -503,7 +503,7 @@ function parseConceptualModelElement(element) { /** Parses a metadata document. * @param handler - This handler. * @param {String} text - Metadata text. - * @returns An object representation of the conceptual model.</returns> + * @returns An object representation of the conceptual model. */ function metadataParser(handler, text) { http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/odata/net-browser.js ---------------------------------------------------------------------- diff --git a/src/lib/odata/net-browser.js b/src/lib/odata/net-browser.js index eec9248..8d956ff 100644 --- a/src/lib/odata/net-browser.js +++ b/src/lib/odata/net-browser.js @@ -41,11 +41,9 @@ var ticks = 0; */ function canUseJSONP(request) { - if (request.method && request.method !== "GET") { - return false; - } + return !(request.method && request.method !== "GET"); + - return true; } /** Creates an IFRAME tag for loading the JSONP script @@ -64,7 +62,7 @@ function createIFrame(url) { writeHtmlToIFrame(iframe, html); return iframe; -}; +} /** Creates a XmlHttpRequest object. * @returns {XmlHttpRequest} XmlHttpRequest object. @@ -129,7 +127,7 @@ function removeCallback(name, tick) { ticks -= 1; } } -}; +} /** Removes an iframe. * @param {Object} iframe - The iframe to remove. @@ -142,7 +140,7 @@ function removeIFrame(iframe) { } return null; -}; +} /** Reads response headers into array. * @param {XMLHttpRequest} xhr - HTTP request with response available. @@ -184,7 +182,12 @@ exports.defaultHttpClient = { * @param {Function} error - Error callback with an error object. * @returns {Object} Object with an 'abort' method for the operation. */ - request: function (request, success, error) { + request: function createRequest() { + + var that = this; + + + return function(request, success, error) { var result = {}; var xhr = null; @@ -217,9 +220,9 @@ exports.defaultHttpClient = { var name; var url = request.requestUri; - var enableJsonpCallback = defined(request.enableJsonpCallback, this.enableJsonpCallback); - var callbackParameterName = defined(request.callbackParameterName, this.callbackParameterName); - var formatQueryString = defined(request.formatQueryString, this.formatQueryString); + var enableJsonpCallback = defined(request.enableJsonpCallback , that.enableJsonpCallback); + var callbackParameterName = defined(request.callbackParameterName, that.callbackParameterName); + var formatQueryString = defined(request.formatQueryString, that.formatQueryString); if (!enableJsonpCallback || isLocalUrl(url)) { xhr = createXmlHttpRequest(); @@ -331,6 +334,7 @@ exports.defaultHttpClient = { return result; } + }() }; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/odata/net.js ---------------------------------------------------------------------- diff --git a/src/lib/odata/net.js b/src/lib/odata/net.js index c3a5863..be45295 100644 --- a/src/lib/odata/net.js +++ b/src/lib/odata/net.js @@ -16,14 +16,14 @@ * specific language governing permissions and limitations * under the License. */ - +'use strict'; /** @module odata/net */ var http = require('http'); var utils = require('./../utils.js'); var url = require("url"); -// Imports. + var defined = utils.defined; var delay = utils.delay; @@ -52,8 +52,8 @@ function canUseJSONP(request) { */ function isAbsoluteUrl(url) { return url.indexOf("http://") === 0 || - url.indexOf("https://") === 0 || - url.indexOf("file://") === 0; + url.indexOf("https://") === 0 || + url.indexOf("file://") === 0; } /** Checks whether the specified URL is local to the current context. @@ -74,15 +74,13 @@ function isLocalUrl(url) { /** Reads response headers into array. - * @param {XMLHttpRequest} xhr - HTTP request with response available. - * @param {Array} headers - Target array to fill with name/value pairs. + * @param {Object} inHeader + * @param {Array} outHeader */ function readResponseHeaders(inHeader, outHeader) { for (var property in inHeader) { if (inHeader.hasOwnProperty(property)) { - //console.log(property); - //console.log(inHeader[property]); outHeader[property] = inHeader[property]; } } @@ -120,11 +118,9 @@ exports.defaultHttpClient = { } - //console.log('options'+JSON.stringify(options)); var xhr = http.request(options); result.abort = function () { - //console.log('_4'); if (done) { return; } @@ -140,7 +136,6 @@ exports.defaultHttpClient = { // Set the timeout if available. if (request.timeoutMS) { - //console.log('_6'); xhr.setTimeout(request.timeoutMS,function () { if (!done) { done = true; @@ -151,40 +146,31 @@ exports.defaultHttpClient = { } xhr.on('error', function(e) { - //console.log('_22'+e); var response = { requestUri: url, statusCode: 400, statusText: e.message }; error({ message: "HTTP request failed", request: request, response: response }); }); xhr.on('response', function (resp) { - //console.log('1'); if (done || xhr === null) { return; } - //console.log('2'); - + var headers = []; readResponseHeaders(resp.headers, headers); var body = ''; resp.on('data', function(chunk) { - ///console.log('chunk'+JSON.stringify(chunk)); body+=chunk; - //console.log('3'); - }); resp.on('end', function() { - //console.log('4'); // do what you do var response = { requestUri: url, statusCode: resp.statusCode, statusText: '', headers: headers, body: body }; done = true; xhr = null; if (resp.statusCode >= 200 && resp.statusCode <= 299) { - //console.log('5'); - //console.log(response); success(response); } else { error({ message: "HTTP request failed", request: request, response: response }); @@ -193,16 +179,11 @@ exports.defaultHttpClient = { }); //xhr.open(request.method || "GET", url, true,); - //console.log(request.body); - //console.log('_1'); if (request.body) { - //console.log('_2'); xhr.write(request.body); } - //console.log('_3'); xhr.end(); - //console.log('_4'); - + return result; } }; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/odata/odatautils.js ---------------------------------------------------------------------- diff --git a/src/lib/odata/odatautils.js b/src/lib/odata/odatautils.js index a44fa05..78b9c5a 100644 --- a/src/lib/odata/odatautils.js +++ b/src/lib/odata/odatautils.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +'use strict'; /** @module odata/utils */ var utils = require('./../utils.js'); @@ -200,10 +201,10 @@ function forEachSchema(metadata, callback) { } /** Formats a millisecond and a nanosecond value into a single string. - * @param {Numaber} ms - Number of milliseconds to format.</param> - * @param {Numaber} ns - Number of nanoseconds to format.</param> + * @param {Number} ms - Number of milliseconds to format. + * @param {Number} ns - Number of nanoseconds to format. * @returns {String} Formatted text. - * If the value is already as string it's returned as-is.</remarks> + * If the value is already as string it's returned as-is. */ function formatMilliseconds(ms, ns) { @@ -400,7 +401,7 @@ var collectionTypeRE = /Collection\((.*)\)/; /** Tests whether a value is a collection value in the library's internal representation. * @param value - Value to test. - * @param {Sting} typeName - Type name of the value. This is used to disambiguate from a collection property value. + * @param {String} typeName - Type name of the value. This is used to disambiguate from a collection property value. * @returns {Boolean} True is the value is a feed value; false otherwise. */ function isCollection(value, typeName) { @@ -464,7 +465,7 @@ function isEntry(value) { /** Tests whether a value is a feed value in the library's internal representation. * @param value - Value to test. - * @param {Sting} typeName - Type name of the value. This is used to disambiguate from a collection property value. + * @param {String} typeName - Type name of the value. This is used to disambiguate from a collection property value. * @returns {Boolean} True is the value is a feed value; false otherwise. */ function isFeed(value, typeName) { @@ -481,11 +482,9 @@ function isFeed(value, typeName) { * @returns {Boolean} True if the type is a geography EDM type; false otherwise. */ function isGeographyEdmType(typeName) { - //check with edm - var ret = contains(geographyEdmTypes, typeName) || + return contains(geographyEdmTypes, typeName) || (typeName.indexOf('.') === -1 && contains(geographyTypes, typeName)); - return ret; } @@ -494,12 +493,12 @@ function isGeographyEdmType(typeName) { * @returns {Boolean} True if the type is a geometry EDM type; false otherwise. */ function isGeometryEdmType(typeName) { - - var ret = contains(geometryEdmTypes, typeName) || + return contains(geometryEdmTypes, typeName) || (typeName.indexOf('.') === -1 && contains(geometryTypes, typeName)); - return ret; } + + /** Tests whether a value is a named stream value in the library's internal representation. * @param value - Value to test. * @returns {Boolean} True is the value is a named stream; false otherwise. @@ -587,7 +586,7 @@ function lookupInMetadata(name, metadata, kind) { } /** Looks up a entity set by name. - * @param {Array} properties - Array of entity set objects as per EDM metadata( may be null) + * @param {Array} entitySets - Array of entity set objects as per EDM metadata( may be null) * @param {String} name - Name to look for. * @returns {Object} The entity set object; null if not found. */ @@ -599,7 +598,7 @@ function lookupEntitySet(entitySets, name) { } /** Looks up a entity set by name. - * @param {Array} properties - Array of entity set objects as per EDM metadata (may be null) + * @param {Array} singletons - Array of entity set objects as per EDM metadata (may be null) * @param {String} name - Name to look for. * @returns {Object} The entity set object; null if not found. */ @@ -613,7 +612,7 @@ function lookupSingleton(singletons, name) { /** Looks up a complex type object by name. * @param {String} name - Name, possibly null or empty. * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. - * @returns A complex type description if the name is found; null otherwise.</returns> + * @returns A complex type description if the name is found; null otherwise. */ function lookupComplexType(name, metadata) { @@ -623,7 +622,7 @@ function lookupComplexType(name, metadata) { /** Looks up an entity type object by name. * @param {String} name - Name, possibly null or empty. * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. - * @returns An entity type description if the name is found; null otherwise.</returns> + * @returns An entity type description if the name is found; null otherwise. */ function lookupEntityType(name, metadata) { @@ -632,9 +631,8 @@ function lookupEntityType(name, metadata) { /** Looks up an - * @param {String} name - Name, possibly null or empty. * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. - * @returns An entity container description if the name is found; null otherwise.</returns> + * @returns An entity container description if the name is found; null otherwise. */ function lookupDefaultEntityContainer(metadata) { @@ -648,7 +646,7 @@ function lookupDefaultEntityContainer(metadata) { /** Looks up an entity container object by name. * @param {String} name - Name, possibly null or empty. * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. - * @returns An entity container description if the name is found; null otherwise.</returns> + * @returns An entity container description if the name is found; null otherwise. */ function lookupEntityContainer(name, metadata) { @@ -656,7 +654,7 @@ function lookupEntityContainer(name, metadata) { } /** Looks up a function import by name. - * @param {Array} properties - Array of function import objects as per EDM metadata (May be null) + * @param {Array} functionImports - Array of function import objects as per EDM metadata (May be null) * @param {String} name - Name to look for. * @returns {Object} The entity set object; null if not found. */ @@ -705,7 +703,9 @@ function lookupNavigationPropertyType(navigationProperty, metadata) { /** Looks up the target entityset name for a navigation property. * @param {Object} navigationProperty - - * @param {Object} metadata - + * @param {Object} sourceEntitySetName - + * @param {Object} metadata - + * metadata * @returns {String} The entityset name for the specified property, null if not found. */ function lookupNavigationPropertyEntitySet(navigationProperty, sourceEntitySetName, metadata) { @@ -734,7 +734,7 @@ function lookupNavigationPropertyEntitySet(navigationProperty, sourceEntitySetNa } /** Gets the entitySet info, container name and functionImports for an entitySet - * @param {Object} navigationProperty - + * @param {Object} entitySetName - * @param {Object} metadata - * @returns {Object} The info about the entitySet. */ @@ -774,7 +774,7 @@ function removeNamespace(ns, fullName) { * @param {String} name - Name (assigned). * @param schema - Schema object as per EDM metadata. * @param {String} kind - Kind of object to look for as per EDM metadata. - * @returns An entity type description if the name is found; null otherwise.</returns> + * @returns An entity type description if the name is found; null otherwise. */ function lookupInSchema(name, schema, kind) { @@ -887,6 +887,7 @@ var parseDateTimeRE = /^(-?\d{4,})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?( /** Parses a string into a DateTime value. * @param {String} value - Value to parse. * @param {Boolean} withOffset - Whether offset is expected. + * @param {Boolean} nullOnError - return null instead of throwing an exception * @returns {Date} The parsed value. */ function parseDateTimeMaybeOffset(value, withOffset, nullOnError) { @@ -971,6 +972,7 @@ function parseDateTimeMaybeOffset(value, withOffset, nullOnError) { /** Parses a string into a Date object. * @param {String} propertyValue - Value to parse. + * @param {Boolean} nullOnError - return null instead of throwing an exception * @returns {Date} The parsed with year, month, day set, time values are set to 0 */ function parseDate(propertyValue, nullOnError) { @@ -990,6 +992,11 @@ function parseDate(propertyValue, nullOnError) { var parseTimeOfDayRE = /^(\d+):(\d+)(:(\d+)(.(\d+))?)?$/; +/**Parses a time into a Date object. + * @param propertyValue + * @param {Boolean} nullOnError - return null instead of throwing an exception + * @returns {{h: Number, m: Number, s: Number, ms: Number}} + */ function parseTimeOfDay(propertyValue, nullOnError) { var parts = parseTimeOfDayRE.exec(propertyValue); @@ -998,15 +1005,14 @@ function parseTimeOfDay(propertyValue, nullOnError) { 'h' :parseInt10(parts[1]), 'm' :parseInt10(parts[2]), 's' :parseInt10(parts[4]), - 'ms' :parseInt10(parts[6]), + 'ms' :parseInt10(parts[6]) }; } /** Parses a string into a DateTimeOffset value. * @param {String} propertyValue - Value to parse. + * @param {Boolean} nullOnError - return null instead of throwing an exception * @returns {Date} The parsed value. - - * The resulting object is annotated with an __edmType property and * an __offset property reflecting the original intended offset of * the value. The time is adjusted for UTC time, as the current @@ -1138,9 +1144,10 @@ function prepareRequest(request, handler, context) { /** Traverses a tree of objects invoking callback for every value. * @param {Object} item - Object or array to traverse. + * @param {Object} owner - Pass through each callback * @param {Function} callback - Callback function with key and value, similar to JSON.parse reviver. * @returns {Object} The object with traversed properties. - Unlike the JSON reviver, this won't delete null members.</remarks> + Unlike the JSON reviver, this won't delete null members. */ function traverseInternal(item, owner, callback) { @@ -1166,7 +1173,7 @@ function traverseInternal(item, owner, callback) { * @param {Object} item - Object or array to traverse. * @param {Function} callback - Callback function with key and value, similar to JSON.parse reviver. * @returns {Object} The traversed object. - * Unlike the JSON reviver, this won't delete null members.</remarks> + * Unlike the JSON reviver, this won't delete null members. */ function traverse(item, callback) { @@ -1263,3 +1270,4 @@ exports.prepareRequest = prepareRequest; exports.removeNamespace = removeNamespace; exports.traverse = traverse; + http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/store.js ---------------------------------------------------------------------- diff --git a/src/lib/store.js b/src/lib/store.js index 5989253..9dd2701 100644 --- a/src/lib/store.js +++ b/src/lib/store.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +//'use strict'; /** @module store */ @@ -49,6 +50,13 @@ exports.createStore = function (name, mechanism) { throw { message: "Failed to create store", name: name, mechanism: mechanism }; }; + +var mechanisms = { + indexeddb: IndexedDBStore, + dom: DomStore, + memory: MemoryStore +}; + exports.mechanisms = mechanisms; @@ -56,8 +64,3 @@ exports.DomStore = DomStore = require('./store/dom.js'); exports.IndexedDBStore = IndexedDBStore = require('./store/indexeddb.js'); exports.MemoryStore = MemoryStore = require('./store/memory.js'); -var mechanisms = { - indexeddb: IndexedDBStore, - dom: DomStore, - memory: MemoryStore -}; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/store/dom.js ---------------------------------------------------------------------- diff --git a/src/lib/store/dom.js b/src/lib/store/dom.js index 355b70e..e14bb6b 100644 --- a/src/lib/store/dom.js +++ b/src/lib/store/dom.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +'use strict'; /** @module store/dom */ @@ -46,7 +47,8 @@ function domStoreDateToJSON() { /** This method is used during JSON parsing and invoked only by the reviver function. * It should never be called directly. * @summary JSON reviver function for converting an object representing a Date in a JSON stream to a Date object - * @param Object - Object to convert. + * @param value _ + * @param value - Object to convert. * @returns {Date} Date object. */ function domStoreJSONToDate(_, value) { @@ -116,8 +118,8 @@ DomStore.isSupported = function () { * @method module:store/dom~DomStore#add * @param {String} key - Key string. * @param value - Value that is going to be added to the store. - * @param {Funcktion} success - Callback for a successful add operation.</param> - * @param {Funcktion} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful add operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. * This method errors out if the store already contains the specified key. */ DomStore.prototype.add = function (key, value, success, error) { @@ -137,8 +139,8 @@ DomStore.prototype.add = function (key, value, success, error) { * @method module:store/dom~DomStore#addOrUpdate * @param {String} key - Key string. * @param value - Value that is going to be added or updated to the store. - * @param {Function} success - Callback for a successful add or update operation.</param> - * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful add or update operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. */ DomStore.prototype.addOrUpdate = function (key, value, success, error) { error = error || this.defaultError; @@ -175,8 +177,8 @@ DomStore.prototype.addOrUpdate = function (key, value, success, error) { /** In case of an error, this method will not restore any keys that might have been deleted at that point. * @summary Removes all the data associated with this store object. * @method module:store/dom~DomStore#clear - * @param {Function} success - Callback for a successful clear operation.</param> - * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful clear operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. */ DomStore.prototype.clear = function (success, error) { @@ -209,8 +211,8 @@ DomStore.prototype.close = function () { /** Checks whether a key exists in the store. * @method module:store/dom~DomStore#contains * @param {String} key - Key string. - * @param {Function} success - Callback indicating whether the store contains the key or not.</param> - * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback indicating whether the store contains the key or not. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. */ DomStore.prototype.contains = function (key, success, error) { error = error || this.defaultError; @@ -227,8 +229,8 @@ DomStore.prototype.defaultError = throwErrorCallback; /** Gets all the keys that exist in the store. * @method module:store/dom~DomStore#getAllKeys - * @param {Function} success - Callback for a successful get operation.</param> - * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful get operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. */ DomStore.prototype.getAllKeys = function (success, error) { @@ -288,8 +290,8 @@ DomStore.prototype.read = function (key, success, error) { /** Removes a key and its value from the store. * @method module:store/dom~DomStore#remove * @param {String} key - Key string. - * @param {Funtion} success - Callback for a successful remove operation.</param> - * @param {Funtion} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful remove operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. */ DomStore.prototype.remove = function (key, success, error) { error = error || this.defaultError; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/store/indexeddb.js ---------------------------------------------------------------------- diff --git a/src/lib/store/indexeddb.js b/src/lib/store/indexeddb.js index 0150e3f..aea0a50 100644 --- a/src/lib/store/indexeddb.js +++ b/src/lib/store/indexeddb.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +'use strict'; /** @module store/indexeddb */ var utils = require('./../utils.js'); @@ -122,7 +123,7 @@ function openStoreDb(store, success, error) { /** Opens a new transaction to the store * @param {IndexedDBStore} store - The store object - * @param {Short} mode - The read/write mode of the transaction (constants from IDBTransaction) + * @param {Integer} mode - The read/write mode of the transaction (constants from IDBTransaction) * @param {Function} success - The success callback * @param {Function} error - The error callback */ @@ -266,6 +267,7 @@ IndexedDBStore.prototype.clear = function (success, error) { transaction.objectStore(name).clear(); }, error); }; + /** Closes the connection to the database * @method module:store/indexeddb~IndexedDBStore#close */ http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/store/memory.js ---------------------------------------------------------------------- diff --git a/src/lib/store/memory.js b/src/lib/store/memory.js index fa49e01..a9c69d4 100644 --- a/src/lib/store/memory.js +++ b/src/lib/store/memory.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +'use strict'; /** @module store/memory */ @@ -68,12 +69,12 @@ function MemoryStore(name) { } /** This method errors out if the store already contains the specified key. - * @summery Adds a new value identified by a key to the store. + * @summary Adds a new value identified by a key to the store. * @method module:store/memory~MemoryStore#add * @param {String} key - Key string. * @param value - Value that is going to be added to the store. - * @param {Function} success - Callback for a successful add operation.</param> - * @param {Function} error - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful add operation. + * @param {Function} error - Callback for handling errors. If not specified then store.defaultError is invoked. */ this.add = function (key, value, success, error) { error = getErrorCallback(error); @@ -92,8 +93,8 @@ function MemoryStore(name) { * @method module:store/memory~MemoryStore#addOrUpdate * @param {String} key - Key string. * @param value - Value that is going to be added or updated to the store. - * @param {Function} success - Callback for a successful add or update operation.</param> - * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful add or update operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. */ this.addOrUpdate = function (key, value, success, error) { @@ -116,7 +117,7 @@ function MemoryStore(name) { /** Removes all the data associated with this store object. * @method module:store/memory~MemoryStore#clear - * @param {Function} success>Callback for a successful clear operation. + * @param {Function} success - Callback for a successful clear operation. */ this.clear = function (success) { items = []; @@ -128,7 +129,7 @@ function MemoryStore(name) { /** Checks whether a key exists in the store. * @method module:store/memory~MemoryStore#contains * @param {String} key - Key string. - * @param {Funktion} success - Callback indicating whether the store contains the key or not.</param> + * @param {Function} success - Callback indicating whether the store contains the key or not. */ this.contains = function (key, success) { var contained = keys.hasOwnProperty(key); @@ -137,7 +138,7 @@ function MemoryStore(name) { /** Gets all the keys that exist in the store. * @method module:store/memory~MemoryStore#getAllKeys - * @param {Function} success - Callback for a successful get operation.</param> + * @param {Function} success - Callback for a successful get operation. */ this.getAllKeys = function (success) { @@ -151,8 +152,8 @@ function MemoryStore(name) { /** Reads the value associated to a key in the store. * @method module:store/memory~MemoryStore#read * @param {String} key - Key string. - * @param {Function} Function - Callback for a successful reads operation.</param> - * @param {Function{}Function - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful reads operation. + * @param {Function} error - Callback for handling errors. If not specified then store.defaultError is invoked. */ this.read = function (key, success, error) { error = getErrorCallback(error); @@ -166,8 +167,8 @@ function MemoryStore(name) { /** Removes a key and its value from the store. * @method module:store/memory~MemoryStore#remove * @param {String} key - Key string. - * @param {Function} success - Callback for a successful remove operation.</param> - * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful remove operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. */ this.remove = function (key, success, error) { error = getErrorCallback(error); @@ -197,8 +198,8 @@ function MemoryStore(name) { * @method module:store/memory~MemoryStore#update * @param {String} key - Key string. * @param value - New value. - * @param {Function} success - Callback for a successful update operation.</param> - * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked.</param> + * @param {Function} success - Callback for a successful update operation. + * @param {Function} [error] - Callback for handling errors. If not specified then store.defaultError is invoked. * This method errors out if the specified key is not found in the store. */ this.update = function (key, value, success, error) { http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/5bff25da/src/lib/utils.js ---------------------------------------------------------------------- diff --git a/src/lib/utils.js b/src/lib/utils.js index 27af705..77b2cde 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +'use strict'; /** @module datajs/utils */ @@ -64,7 +65,7 @@ function contains(arr, item) { /** Given two values, picks the first one that is not undefined. * @param a - First value. * @param b - Second value. - * @returns a if it's a defined value; else b.</returns> + * @returns a if it's a defined value; else b. */ function defined(a, b) { return (a !== undefined) ? a : b; @@ -187,7 +188,7 @@ function throwErrorCallback(error) { } /** Removes leading and trailing whitespaces from a string. - * @param {String str String to trim + * @param {String} str String to trim * @returns {String} The string with no leading or trailing whitespace. */ function trimString(str) { @@ -343,7 +344,7 @@ function normalizeURI(uri, base) { } /** Merges the path of a relative URI and a base URI. - * @param {String} uriPath - Relative URI path.</param> + * @param {String} uriPath - Relative URI path. * @param {String} basePath - Base URI path. * @returns {String} A string with the merged path. */
