<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>JSDoc: Source: odata/json.js</title> | |
<script src="scripts/prettify/prettify.js"> </script> | |
<script src="scripts/prettify/lang-css.js"> </script> | |
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> | |
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> | |
</head> | |
<body> | |
<div id="main"> | |
<h1 class="page-title">Source: odata/json.js</h1> | |
<section> | |
<article> | |
<pre class="prettyprint source"><code>/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
/** @module odata/json */ | |
var utils = require('./../utils.js'); | |
var oDataUtils = require('./odatautils.js'); | |
var oDataHandler = require('./handler.js'); | |
var odataNs = "odata"; | |
var odataAnnotationPrefix = odataNs + "."; | |
var contextUrlAnnotation = "@" + odataAnnotationPrefix + "context"; | |
var assigned = utils.assigned; | |
var defined = utils.defined; | |
var isArray = utils.isArray; | |
//var isDate = utils.isDate; | |
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; | |
var formatNumberWidth = oDataUtils.formatNumberWidth; | |
var getCanonicalTimezone = oDataUtils.getCanonicalTimezone; | |
var handler = oDataUtils.handler; | |
var isComplex = oDataUtils.isComplex; | |
var isPrimitive = oDataUtils.isPrimitive; | |
var isCollectionType = oDataUtils.isCollectionType; | |
var lookupComplexType = oDataUtils.lookupComplexType; | |
var lookupEntityType = oDataUtils.lookupEntityType; | |
var lookupSingleton = oDataUtils.lookupSingleton; | |
var lookupEntitySet = oDataUtils.lookupEntitySet; | |
var lookupDefaultEntityContainer = oDataUtils.lookupDefaultEntityContainer; | |
var lookupProperty = oDataUtils.lookupProperty; | |
var MAX_DATA_SERVICE_VERSION = oDataUtils.MAX_DATA_SERVICE_VERSION; | |
var maxVersion = oDataUtils.maxVersion; | |
var isPrimitiveEdmType = oDataUtils.isPrimitiveEdmType; | |
var isGeographyEdmType = oDataUtils.isGeographyEdmType; | |
var isGeometryEdmType = oDataUtils.isGeometryEdmType; | |
var PAYLOADTYPE_FEED = "f"; | |
var PAYLOADTYPE_ENTRY = "e"; | |
var PAYLOADTYPE_PROPERTY = "p"; | |
var PAYLOADTYPE_COLLECTION = "c"; | |
var PAYLOADTYPE_ENUMERATION_PROPERTY = "enum"; | |
var PAYLOADTYPE_SVCDOC = "s"; | |
var PAYLOADTYPE_ENTITY_REF_LINK = "erl"; | |
var PAYLOADTYPE_ENTITY_REF_LINKS = "erls"; | |
var PAYLOADTYPE_VALUE = "v"; | |
var PAYLOADTYPE_DELTA = "d"; | |
var DELTATYPE_FEED = "f"; | |
var DELTATYPE_DELETED_ENTRY = "de"; | |
var DELTATYPE_LINK = "l"; | |
var DELTATYPE_DELETED_LINK = "dl"; | |
var jsonMediaType = "application/json"; | |
var jsonContentType = oDataHandler.contentType(jsonMediaType); | |
var jsonSerializableMetadata = ["@odata.id", "@odata.type"]; | |
/** 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. | |
*/ | |
function jsonParser(handler, text, context) { | |
var recognizeDates = defined(context.recognizeDates, handler.recognizeDates); | |
var model = context.metadata; | |
var json = (typeof text === "string") ? JSON.parse(text) : text; | |
var metadataContentType; | |
if (assigned(context.contentType) && assigned(context.contentType.properties)) { | |
metadataContentType = context.contentType.properties["odata.metadata"]; //TODO convert to lower before comparism | |
} | |
var payloadFormat = getFormatKind(metadataContentType, 1); // none: 0, minimal: 1, full: 2 | |
// No errors should be throw out if we could not parse the json payload, instead we should just return the original json object. | |
if (payloadFormat === 0) { | |
return json; | |
} | |
else if (payloadFormat === 1) { | |
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 addFullMetadataToJsonPayload(json, model, recognizeDates); | |
} | |
else { | |
return json; | |
} | |
} | |
// 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; | |
} | |
/** 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; | |
} | |
/** Determine form the attribute name if the attribute is a serializable property | |
* @param attribute | |
* @returns {boolean} | |
*/ | |
function isJsonSerializableProperty(attribute) { | |
if (!attribute) { | |
return false; | |
} | |
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 }; | |
} | |
/** 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 addFullMetadataToJsonPayload(data, model, recognizeDates) { | |
var type; | |
if (utils.isObject(data)) { | |
for (var key in data) { | |
if (data.hasOwnProperty(key)) { | |
if (key.indexOf('@') === -1) { | |
if (utils.isArray(data[key])) { | |
for (var i = 0; i < data[key].length; ++i) { | |
addFullMetadataToJsonPayload(data[key][i], model, recognizeDates); | |
} | |
} else if (utils.isObject(data[key])) { | |
if (data[key] !== null) { | |
//don't step into geo.. objects | |
type = data[key+'@odata.type']; | |
if (!type) { | |
//type unknown | |
addFullMetadataToJsonPayload(data[key], model, recognizeDates); | |
} else { | |
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. | |
// 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. | |
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 | |
addType(data, key, 'Int32'); // the biggst integer | |
} else { | |
addType(data, key, 'Decimal'); // the biggst float single,doulbe,decimal | |
} | |
} | |
} | |
else { | |
if (recognizeDates) { | |
convertDatesNoEdm(data, key, type.substring(1)); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
return 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 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++) { | |
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); | |
} | |
} | |
} | |
} | |
} | |
/** 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) { | |
if (!assigned(model) || isArray(model)) { | |
return data; | |
} | |
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; | |
} | |
/** 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; | |
} | |
/** 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 addMetadataToJsonMinimalPayloadComplex(data, property, baseURI, model, recognizeDates) { | |
var type = property.type; | |
if (isCollectionType(property.type)) { | |
type =property.type.substring(11,property.type.length-1); | |
} | |
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) { | |
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 addType(data, name, value ) { | |
var fullName = name + '@odata.type'; | |
if ( data[fullName] === undefined) { | |
data[fullName] = '#' + value; | |
} | |
} | |
/** 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 | |
* @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 = {}; | |
if (fragments.indexOf('/') === -1 ) { | |
if (fragments.length === 0) { | |
// Capter 10.1 | |
ret.detectedPayloadKind = PAYLOADTYPE_SVCDOC; | |
return ret; | |
} else if (fragments === 'Edm.Null') { | |
// Capter 10.15 | |
ret.detectedPayloadKind = PAYLOADTYPE_VALUE; | |
ret.isNullProperty = true; | |
return ret; | |
} else if (fragments === 'Collection($ref)') { | |
// Capter 10.11 | |
ret.detectedPayloadKind = PAYLOADTYPE_ENTITY_REF_LINKS; | |
return ret; | |
} else if (fragments === '$ref') { | |
// Capter 10.12 | |
ret.detectedPayloadKind = PAYLOADTYPE_ENTITY_REF_LINK; | |
return ret; | |
} 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) { | |
//preparation | |
if ( fragment.indexOf('(') !== -1 ) { | |
//remove the query function, cut fragment to matching '(' | |
var index = fragment.length - 2 ; | |
for ( var rCount = 1; rCount > 0 && index > 0; --index) { | |
if ( fragment.charAt(index)=='(') { | |
rCount --; | |
} else if ( fragment.charAt(index)==')') { | |
rCount ++; | |
} | |
} | |
if (index === 0) { | |
//TODO throw error | |
} | |
//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); | |
if (utils.startsWith(fragment, 'Collection')) { | |
ret.detectedPayloadKind = PAYLOADTYPE_COLLECTION; | |
// Capter 10.14 | |
ret.typeName = inPharenthesis; | |
type = lookupEntityType(ret.typeName, model); | |
if ( type !== null) { | |
ret.type = type; | |
continue; | |
} | |
type = lookupComplexType(ret.typeName, model); | |
if ( type !== null) { | |
ret.type = type; | |
continue; | |
} | |
ret.type = null;//in case of #Collection(Edm.String) only lastTypeName is filled | |
continue; | |
} else { | |
// projection: Capter 10.7, 10.8 and 10.9 | |
ret.projection = inPharenthesis; | |
} | |
} | |
if (jsonIsPrimitiveType(fragment)) { | |
ret.typeName = fragment; | |
ret.type = null; | |
ret.detectedPayloadKind = PAYLOADTYPE_VALUE; | |
continue; | |
} | |
var container = lookupDefaultEntityContainer(model); | |
//check for entity | |
var entitySet = lookupEntitySet(container.entitySet, fragment); | |
if ( entitySet !== null) { | |
ret.typeName = entitySet.entityType; | |
ret.type = lookupEntityType( ret.typeName, model); | |
ret.name = fragment; | |
ret.detectedPayloadKind = PAYLOADTYPE_FEED; | |
// Capter 10.2 | |
continue; | |
} | |
//check for singleton | |
var singleton = lookupSingleton(container.singleton, fragment); | |
if ( singleton !== null) { | |
ret.typeName = singleton.entityType; | |
ret.type = lookupEntityType( ret.typeName, model); | |
ret.name = fragment; | |
ret.detectedPayloadKind = PAYLOADTYPE_ENTRY; | |
// Capter 10.4 | |
continue; | |
} | |
//TODO throw ERROR | |
} else { | |
//check for $entity | |
if (utils.endsWith(fragment, '$entity') && (ret.detectedPayloadKind === PAYLOADTYPE_FEED)) { | |
//TODO ret.name = fragment; | |
ret.detectedPayloadKind = PAYLOADTYPE_ENTRY; | |
// Capter 10.3 and 10.6 | |
continue; | |
} | |
//check for derived types | |
if (fragment.indexOf('.') !== -1) { | |
// Capter 10.6 | |
ret.typeName = fragment; | |
type = lookupEntityType(ret.typeName, model); | |
if ( type !== null) { | |
ret.type = type; | |
continue; | |
} | |
type = lookupComplexType(ret.typeName, model); | |
if ( type !== null) { | |
ret.type = type; | |
continue; | |
} | |
//TODO throw ERROR invalid type | |
} | |
//check for property value | |
if ( ret.detectedPayloadKind === PAYLOADTYPE_FEED || ret.detectedPayloadKind === PAYLOADTYPE_ENTRY) { | |
var property = lookupProperty(ret.type.property, fragment); | |
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.detectedPayloadKind = PAYLOADTYPE_COLLECTION; | |
} else { | |
ret.type = lookupComplexType(property.type, model); | |
ret.detectedPayloadKind = PAYLOADTYPE_PROPERTY; | |
} | |
ret.name = fragment; | |
// Capter 10.15 | |
} | |
continue; | |
} | |
if (fragment === '$delta') { | |
ret.deltaKind = DELTATYPE_FEED; | |
continue; | |
} else if (utils.endsWith(fragment, '/$deletedEntity')) { | |
ret.deltaKind = DELTATYPE_DELETED_ENTRY; | |
continue; | |
} else if (utils.endsWith(fragment, '/$link')) { | |
ret.deltaKind = DELTATYPE_LINK; | |
continue; | |
} else if (utils.endsWith(fragment, '/$deletedLink')) { | |
ret.deltaKind = DELTATYPE_DELETED_LINK; | |
continue; | |
} | |
//TODO throw ERROr | |
} | |
} | |
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. | |
* If the arguments passed to the function don't convey enough information about the payload to determine without doubt that the payload is a feed then it | |
* will try to use the payload object structure instead. If the payload looks like a feed (has value property that is an array or non-primitive values) then | |
* 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; | |
} | |
var fragmentStart = metadataUri.lastIndexOf("#"); | |
if (fragmentStart === -1) { | |
return jsonMakePayloadInfo(PAYLOADTYPE_SVCDOC); | |
} | |
var fragment = metadataUri.substring(fragmentStart + 1); | |
return parseContextUriFragment(fragment,model); | |
} | |
/** 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) { | |
var entityInstanceKey; | |
var entityKeys = entityModel.key[0].propertyRef; | |
var type; | |
entityInstanceKey = "("; | |
if (entityKeys.length == 1) { | |
type = lookupProperty(entityModel.property, entityKeys[0].name).type; | |
entityInstanceKey += formatLiteral(data[entityKeys[0].name], type); | |
} else { | |
var first = true; | |
for (var i = 0; i < entityKeys.length; i++) { | |
if (!first) { | |
entityInstanceKey += ","; | |
} else { | |
first = false; | |
} | |
type = lookupProperty(entityModel.property, entityKeys[i].name).type; | |
entityInstanceKey += entityKeys[i].name + "=" + formatLiteral(data[entityKeys[i].name], type); | |
} | |
} | |
entityInstanceKey += ")"; | |
return entityInstanceKey; | |
} | |
/** 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); | |
} | |
var jsonHandler = oDataHandler.handler(jsonParser, jsonSerializer, jsonMediaType, MAX_DATA_SERVICE_VERSION); | |
jsonHandler.recognizeDates = false; | |
exports.createPayloadInfo = createPayloadInfo; | |
exports.jsonHandler = jsonHandler; | |
exports.jsonParser = jsonParser; | |
exports.jsonSerializer = jsonSerializer; | |
exports.parseJsonDateString = parseJsonDateString;</code></pre> | |
</article> | |
</section> | |
</div> | |
<nav> | |
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="module-cache.html">cache</a></li><li><a href="source.html">cache/source</a></li><li><a href="module-odata.html">odata</a></li><li><a href="batch.html">odata/batch</a></li><li><a href="handler.html">odata/handler</a></li><li><a href="json.html">odata/json</a></li><li><a href="metadata.html">odata/metadata</a></li><li><a href="net.html">odata/net</a></li><li><a href="utils.html">odata/utils</a></li><li><a href="deferred.html">odatajs/deferred</a></li><li><a href="utils_.html">odatajs/utils</a></li><li><a href="xml.html">odatajs/xml</a></li><li><a href="module-store.html">store</a></li><li><a href="dom.html">store/dom</a></li><li><a href="indexeddb.html">store/indexeddb</a></li><li><a href="memory.html">store/memory</a></li></ul><h3>Classes</h3><ul><li><a href="DataCache.html">DataCache</a></li><li><a href="DataCacheOperation.html">DataCacheOperation</a></li><li><a href="DjsDeferred.html">DjsDeferred</a></li><li><a href="dom-DomStore.html">DomStore</a></li><li><a href="indexeddb-IndexedDBStore.html">IndexedDBStore</a></li><li><a href="memory-MemoryStore.html">MemoryStore</a></li><li><a href="ODataCacheSource.html">ODataCacheSource</a></li></ul><h3><a href="global.html">Global</a></h3> | |
</nav> | |
<br clear="both"> | |
<footer> | |
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Thu Apr 09 2015 08:31:26 GMT+0200 (MESZ) | |
</footer> | |
<script> prettyPrint(); </script> | |
<script src="scripts/linenumber.js"> </script> | |
</body> | |
</html> |