blob: 620ae634258645975b48fde7a95448354b08cb12 [file] [log] [blame]
/*
* 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.
*/
/* {
oldname:'odata-json-light.js',
updated:'20140514 12:59'
}*/
var utils = require('./../datajs.js').utils;
var oDataUtils = require('./utils.js');
var assigned = utils.assigned;
var djsassert = utils.djsassert;
var extend = utils.extend;
var getURIInfo = utils.getURIInfo;
var isArray = utils.isArray;
var isDate = utils.isDate;
var isObject = utils.isObject;
var normalizeURI = utils.normalizeURI;
var renameProperty = utils.renameProperty;
var undefinedDefault = utils.undefinedDefault;
var convertByteArrayToHexString = utils.convertByteArrayToHexString;
var dataItemTypeName = oDataUtils.dataItemTypeName;
var EDM_DATETIME = oDataUtils.EDM_DATETIME;
var EDM_DATETIMEOFFSET = oDataUtils.EDM_DATETIMEOFFSET;
var EDM_TIME = oDataUtils.EDM_TIME;
var getCollectionType = oDataUtils.getCollectionType;
var isCollection = oDataUtils.isCollection;
var isCollectionType = oDataUtils.isCollectionType;
var isComplex = oDataUtils.isComplex;
var isDeferred = oDataUtils.isDeferred;
var isFeed = oDataUtils.isFeed;
var isEntry = oDataUtils.isEntry;
var isGeographyEdmType = oDataUtils.isGeographyEdmType;
var isGeometryEdmType = oDataUtils.isGeometryEdmType;
var isPrimitiveEdmType = oDataUtils.isPrimitiveEdmType;
var isPrimitive = oDataUtils.isPrimitive;
var lookupComplexType = oDataUtils.lookupComplexType;
var lookupDefaultEntityContainer = oDataUtils.lookupDefaultEntityContainer;
var lookupEntityContainer = oDataUtils.lookupEntityContainer;
var lookupEntitySet = oDataUtils.lookupEntitySet;
var lookupSingleton = oDataUtils.lookupSingleton;
var lookupEntityType = oDataUtils.lookupEntityType;
var lookupFunctionImport = oDataUtils.lookupFunctionImport;
var lookupNavigationPropertyType = oDataUtils.lookupNavigationPropertyType;
var getEntitySetInfo = oDataUtils.getEntitySetInfo;
var lookupNavigationPropertyEntitySet = oDataUtils.lookupNavigationPropertyEntitySet;
var lookupProperty = oDataUtils.lookupProperty;
var parseBool = oDataUtils.parseBool;
var parseDateTime = oDataUtils.parseDateTime;
var parseDateTimeOffset = oDataUtils.parseDateTimeOffset;
var parseDuration = oDataUtils.parseDuration;
// CONTENT START
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 odataNs = "odata";
var odataAnnotationPrefix = odataNs + ".";
var contextUrlAnnotation = "@" + odataAnnotationPrefix + "context";
var bindAnnotation = "@" + odataAnnotationPrefix + "bind";
var navUrlAnnotation = odataAnnotationPrefix + "navigationLinkUrl";
var typeAnnotation = odataAnnotationPrefix + "type";
var jsonLightNameMap = {
readLink: "self",
editLink: "edit",
nextLink: "__next",
mediaReadLink: "media_src",
mediaEditLink: "edit_media",
mediaContentType: "content_type",
mediaETag: "media_etag",
count: "__count",
media_src: "mediaReadLink",
edit_media: "mediaEditLink",
content_type: "mediaContentType",
media_etag: "mediaETag",
url: "uri"
};
var jsonLightAnnotations = {
metadata: "odata.metadata",
count: "odata.count",
next: "odata.nextLink",
id: "odata.id",
etag: "odata.etag",
read: "odata.readLink",
edit: "odata.editLink",
mediaRead: "odata.mediaReadLink",
mediaEdit: "odata.mediaEditLink",
mediaEtag: "odata.mediaETag",
mediaContentType: "odata.mediaContentType",
actions: "odata.actions",
functions: "odata.functions",
navigationUrl: "odata.navigationLinkUrl",
associationUrl: "odata.associationLinkUrl",
type: "odata.type"
};
var jsonLightAnnotationInfo = function (annotation) {
/// <summary>Gets the name and target of an annotation in a JSON light payload.</summary>
/// <param name="annotation" type="String">JSON light payload annotation.</param>
/// <returns type="Object">Object containing the annotation name and the target property name.</param>
if (annotation.indexOf(".") > 0) {
var targetEnd = annotation.indexOf("@");
var target = targetEnd > -1 ? annotation.substring(0, targetEnd) : null;
var name = annotation.substring(targetEnd + 1);
return {
target: target,
name: name,
isOData: name.indexOf(odataAnnotationPrefix) === 0
};
}
return null;
};
var jsonLightDataItemType = function (name, value, container, dataItemModel, model) {
/// <summary>Gets the type name of a JSON light data item that belongs to a feed, an entry, a complex type property, or a collection property.</summary>
/// <param name="name" type="String">Name of the data item for which the type name is going to be retrieved.</param>
/// <param name="value">Value of the data item.</param>
/// <param name="container" type="Object">JSON light object that owns the data item.</param>
/// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <remarks>
/// This function will first try to get the type name from the data item's value itself if it is a JSON light object; otherwise
/// it will try to get it from the odata.type annotation applied to the data item in the container. Then, it will fallback to the data item model.
/// If all attempts fail, it will return null.
/// </remarks>
/// <returns type="String">Data item type name; null if the type name cannot be found.</returns>
return (isComplex(value) && value[typeAnnotation]) ||
(container && container[name + "@" + typeAnnotation]) ||
(dataItemModel && dataItemModel.type) ||
(lookupNavigationPropertyType(dataItemModel, model)) ||
null;
};
var jsonLightDataItemModel = function (name, containerModel) {
/// <summary>Gets an object describing a data item in an OData conceptual schema.</summary>
/// <param name="name" type="String">Name of the data item for which the model is going to be retrieved.</param>
/// <param name="containerModel" type="Object">Object describing the owner of the data item in an OData conceptual schema.</param>
/// <returns type="Object">Object describing the data item; null if it cannot be found.</returns>
if (containerModel) {
return lookupProperty(containerModel.property, name) ||
lookupProperty(containerModel.navigationProperty, name);
}
return null;
};
var jsonLightIsEntry = function (data) {
/// <summary>Determines whether data represents a JSON light entry object.</summary>
/// <param name="data" type="Object">JSON light object to test.</param>
/// <returns type="Boolean">True if the data is JSON light entry object; false otherwise.</returns>
return isComplex(data) && ((odataAnnotationPrefix + "id") in data);
};
/*
var jsonLightIsNavigationProperty = function (name, data, dataItemModel) {
/// <summary>Determines whether a data item in a JSON light object is a navigation property.</summary>
/// <param name="name" type="String">Name of the data item to test.</param>
/// <param name="data" type="Object">JSON light object that owns the data item.</param>
/// <param name="dataItemModel" type="Object">Object describing the data item in an OData conceptual schema.</param>
/// <returns type="Boolean">True if the data item is a navigation property; false otherwise.</returns>
djsassert(isComplex(data), "jsonLightIsNavProp - data is not an object!!");
if (!!data[name + "@" + navUrlAnnotation] || (dataItemModel && dataItemModel.relationship)) {
return true;
}
// Sniff the property value.
var value = isArray(data[name]) ? data[name][0] : data[name];
return jsonLightIsEntry(value);
};
*/
var jsonLightIsPrimitiveType = function (typeName) {
/// <summary>Determines whether a type name is a primitive type in a JSON light payload.</summary>
/// <param name="typeName" type="String">Type name to test.</param>
/// <returns type="Boolean">True if the type name an EDM primitive type or an OData spatial type; false otherwise.</returns>
return isPrimitiveEdmType(typeName) || isGeographyEdmType(typeName) || isGeometryEdmType(typeName);
};
var jsonLightReadDataAnnotations = function (data, obj, baseURI, dataModel, model) {
/// <summary>Converts annotations found in a JSON light payload object to either properties or metadata.</summary>
/// <param name="data" type="Object">JSON light payload object containing the annotations to convert.</param>
/// <param name="obj" type="Object">Object that will store the converted annotations.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="dataModel" type="Object">Object describing the JSON light payload in an OData conceptual schema.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <returns>JSON light payload object with its annotations converted to either properties or metadata.</param>
for (var name in data) {
if (name.indexOf(".") > 0 && name.charAt(0) !== "#") {
var annotationInfo = jsonLightAnnotationInfo(name);
if (annotationInfo) {
var annotationName = annotationInfo.name;
var target = annotationInfo.target;
var targetModel = null;
var targetType = null;
if (target) {
targetModel = jsonLightDataItemModel(target, dataModel);
targetType = jsonLightDataItemType(target, data[target], data, targetModel, model);
}
if (annotationInfo.isOData) {
jsonLightApplyPayloadODataAnnotation(annotationName, target, targetType, data[name], data, obj, baseURI);
} else {
obj[name] = data[name];
}
}
}
}
return obj;
};
var jsonLightApplyPayloadODataAnnotation = function (name, target, targetType, value, data, obj, baseURI) {
/// <summary>
/// Processes a JSON Light payload OData annotation producing either a property, payload metadata, or property metadata on its owner object.
/// </summary>
/// <param name="name" type="String">Annotation name.</param>
/// <param name="target" type="String">Name of the property that is being targeted by the annotation.</param>
/// <param name="targetType" type="String">Type name of the target property.</param>
/// <param name="data" type="Object">JSON light object containing the annotation.</param>
/// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
var annotation = name.substring(odataAnnotationPrefix.length);
switch (annotation) {
case "navigationLinkUrl":
jsonLightApplyNavigationUrlAnnotation(annotation, target, targetType, value, data, obj, baseURI);
return;
case "nextLink":
case "count":
jsonLightApplyFeedAnnotation(annotation, target, value, obj, baseURI);
return;
case "mediaReadLink":
case "mediaEditLink":
case "mediaContentType":
case "mediaETag":
jsonLightApplyMediaAnnotation(annotation, target, targetType, value, obj, baseURI);
return;
default:
jsonLightApplyMetadataAnnotation(annotation, target, value, obj, baseURI);
return;
}
};
var jsonLightApplyMetadataAnnotation = function (name, target, value, obj, baseURI) {
/// <summary>
/// Converts a JSON light annotation that applies to entry metadata only (i.e. odata.editLink or odata.readLink) and its value
/// into their library's internal representation and saves it back to data.
/// </summary>
/// <param name="name" type="String">Annotation name.</param>
/// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
/// <param name="value" type="Object">Annotation value.</param>
/// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
var metadata = obj.__metadata = obj.__metadata || {};
var mappedName = jsonLightNameMap[name] || name;
if (name === "editLink") {
metadata.uri = normalizeURI(value, baseURI);
metadata[mappedName] = metadata.uri;
return;
}
if (name === "readLink" || name === "associationLinkUrl") {
value = normalizeURI(value, baseURI);
}
if (target) {
var propertiesMetadata = metadata.properties = metadata.properties || {};
var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
if (name === "type") {
propertyMetadata[mappedName] = propertyMetadata[mappedName] || value;
return;
}
propertyMetadata[mappedName] = value;
return;
}
metadata[mappedName] = value;
};
var jsonLightApplyFeedAnnotation = function (name, target, value, obj, baseURI) {
/// <summary>
/// Converts a JSON light annotation that applies to feeds only (i.e. odata.count or odata.nextlink) and its value
/// into their library's internal representation and saves it back to data.
/// </summary>
/// <param name="name" type="String">Annotation name.</param>
/// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
/// <param name="value" type="Object">Annotation value.</param>
/// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
var mappedName = jsonLightNameMap[name];
var feed = target ? obj[target] : obj;
feed[mappedName] = (name === "nextLink") ? normalizeURI(value, baseURI) : value;
};
var jsonLightApplyMediaAnnotation = function (name, target, targetType, value, obj, baseURI) {
/// <summary>
/// Converts a JSON light media annotation in and its value into their library's internal representation
/// and saves it back to data or metadata.
/// </summary>
/// <param name="name" type="String">Annotation name.</param>
/// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
/// <param name="targetType" type="String">Type name of the target property.</param>
/// <param name="value" type="Object">Annotation value.</param>
/// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
var metadata = obj.__metadata = obj.__metadata || {};
var mappedName = jsonLightNameMap[name];
if (name === "mediaReadLink" || name === "mediaEditLink") {
value = normalizeURI(value, baseURI);
}
if (target) {
var propertiesMetadata = metadata.properties = metadata.properties || {};
var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
propertyMetadata.type = propertyMetadata.type || targetType;
obj.__metadata = metadata;
obj[target] = obj[target] || { __mediaresource: {} };
obj[target].__mediaresource[mappedName] = value;
return;
}
metadata[mappedName] = value;
};
var jsonLightApplyNavigationUrlAnnotation = function (name, target, targetType, value, data, obj, baseURI) {
/// <summary>
/// Converts a JSON light navigation property annotation and its value into their library's internal representation
/// and saves it back to data o metadata.
/// </summary>
/// <param name="name" type="String">Annotation name.</param>
/// <param name="target" type="String">Name of the property on which the annotation should be applied.</param>
/// <param name="targetType" type="String">Type name of the target property.</param>
/// <param name="value" type="Object">Annotation value.</param>
/// <param name="data" type="Object">JSON light object containing the annotation.</param>
/// <param name="obj" type="Object">Object that will hold properties produced by the annotation.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
var metadata = obj.__metadata = obj.__metadata || {};
var propertiesMetadata = metadata.properties = metadata.properties || {};
var propertyMetadata = propertiesMetadata[target] = propertiesMetadata[target] || {};
var uri = normalizeURI(value, baseURI);
if (data.hasOwnProperty(target)) {
// The navigation property is inlined in the payload,
// so the navigation link url should be pushed to the object's
// property metadata instead.
propertyMetadata.navigationLinkUrl = uri;
return;
}
obj[target] = { __deferred: { uri: uri} };
propertyMetadata.type = propertyMetadata.type || targetType;
};
var jsonLightReadDataItemValue = function (value, typeName, dataItemMetadata, baseURI, dataItemModel, model, recognizeDates) {
/// <summary>Converts the value of a data item in a JSON light object to its library representation.</summary>
/// <param name="value">Data item value to convert.</param>
/// <param name="typeName" type="String">Type name of the data item.</param>
/// <param name="dataItemMetadata" type="Object">Object containing metadata about the data item.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns>Data item value in its library representation.</param>
if (typeof value === "string") {
return jsonLightReadStringPropertyValue(value, typeName, recognizeDates);
}
if (!jsonLightIsPrimitiveType(typeName)) {
if (isArray(value)) {
return jsonLightReadCollectionPropertyValue(value, typeName, dataItemMetadata, baseURI, model, recognizeDates);
}
if (isComplex(value)) {
return jsonLightReadComplexPropertyValue(value, typeName, dataItemMetadata, baseURI, model, recognizeDates);
}
}
return value + typeName;
};
var jsonLightReadStringPropertyValue = function (value, propertyType, recognizeDates) {
/// <summary>Convertes the value of a string property in a JSON light object to its library representation.</summary>
/// <param name="value" type="String">String value to convert.</param>
/// <param name="propertyType" type="String">Type name of the property.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns>String property value in its library representation.</returns>
switch (propertyType) {
case EDM_TIME:
return parseDuration(value);
case EDM_DATETIME:
return parseDateTime(value, /*nullOnError*/false);
case EDM_DATETIMEOFFSET:
return parseDateTimeOffset(value, /*nullOnError*/false);
}
if (recognizeDates) {
return parseDateTime(value, /*nullOnError*/true) ||
parseDateTimeOffset(value, /*nullOnError*/true) ||
value;
}
return value;
};
var jsonLightReadCollectionPropertyValue = function (value, propertyType, propertyMetadata, baseURI, model, recognizeDates) {
/// <summary>Converts the value of a collection property in a JSON light object into its library representation.</summary>
/// <param name="value" type="Array">Collection property value to convert.</param>
/// <param name="propertyType" type="String">Property type name.</param>
/// <param name="propertyMetadata" type="Object">Object containing metadata about the collection property.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns type="Object">Collection property value in its library representation.</returns>
var collectionType = getCollectionType(propertyType);
var itemsMetadata = [];
var items = [];
var i, len;
for (i = 0, len = value.length; i < len; i++) {
var itemType = jsonLightDataItemType(null, value[i]) || collectionType;
var itemMetadata = { type: itemType };
var item = jsonLightReadDataItemValue(value[i], itemType, itemMetadata, baseURI, null, model, recognizeDates);
if (!jsonLightIsPrimitiveType(itemType) && !isPrimitive(value[i])) {
itemsMetadata.push(itemMetadata);
}
items.push(item);
}
if (itemsMetadata.length > 0) {
propertyMetadata.elements = itemsMetadata;
}
return { __metadata: { type: propertyType }, results: items };
};
var jsonLightReadComplexPropertyValue = function (value, propertyType, propertyMetadata, baseURI, model, recognizeDates) {
/// <summary>Converts the value of a comples property in a JSON light object into its library representation.</summary>
/// <param name="value" type="Object">Complex property value to convert.</param>
/// <param name="propertyType" type="String">Property type name.</param>
/// <param name="propertyMetadata" type="Object">Object containing metadata about the complx type property.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns type="Object">Complex property value in its library representation.</returns>
var complexValue = jsonLightReadObject(value, { type: propertyType }, baseURI, model, recognizeDates);
var complexMetadata = complexValue.__metadata;
var complexPropertiesMetadata = complexMetadata.properties;
if (complexPropertiesMetadata) {
propertyMetadata.properties = complexPropertiesMetadata;
delete complexMetadata.properties;
}
return complexValue;
};
var jsonLightReadNavigationPropertyValue = function (value, propertyInfo, baseURI, model, recognizeDates) {
/// <summary>Converts the value of a navigation property in a JSON light object into its library representation.</summary>
/// <param name="value">Navigation property property value to convert.</param>
/// <param name="propertyInfo" type="String">Information about the property whether it's an entry, feed or complex type.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns type="Object">Collection property value in its library representation.</returns>
if (isArray(value)) {
return jsonLightReadFeed(value, propertyInfo, baseURI, model, recognizeDates);
}
if (isComplex(value)) {
return jsonLightReadObject(value, propertyInfo, baseURI, model, recognizeDates);
}
return null;
};
var jsonLightReadComplexObjectNew = function (data, property, baseURI, model, demandedFormat, recognizeDates) {
var type = property.type;
if (isCollectionType(property.type)) {
type =property.type.substring(11,property.type.length-1);
}
data['@odata.type'] = '#'+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
}
var curType = propertyType;
for (var name in data) {
if (name.indexOf("@") === -1) {
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 (demandedFormat === 3) {
if ( isArray(propertyValue)) {
data[name+'@odata.type'] = '#' + property.type;
for ( var i = 0; i < propertyValue.length; i++) {
jsonLightReadComplexObjectNew(propertyValue[0], property,baseURI,model,demandedFormat, recognizeDates);
}
} else if (isObject(propertyValue) && (propertyValue!= null)) {
jsonLightReadComplexObjectNew(propertyValue, property,baseURI,model,demandedFormat, recognizeDates);
} else {
data[name+'@odata.type'] = '#' + property.type;
}
} else {
}
}
}
}
var jsonLightReadObjectNew = function (data, objectInfo, baseURI, model, demandedFormat, recognizeDates) {
//var obj = {};
data['@odata.type'] = '#'+objectInfo.typeName;
var keyType = objectInfo.type;
while (( keyType.key === undefined) && (keyType.baseType !== undefined)) {
keyType = lookupEntityType(keyType.baseType, model);
}
var lastIdSegment = objectInfo.name + jsonLightGetEntryKey(data, keyType);
data['@odata.id'] = baseURI.substring(0, baseURI.lastIndexOf("$metadata")) + lastIdSegment;
data['@odata.editLink'] = lastIdSegment;
var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata"));
//jsonLightComputeUrisIfMissing(data, entryInfo, actualType, serviceURI, dataModel, baseTypeModel);
for (var name in data) {
if (name.indexOf("@") === -1) {
var curType = objectInfo.type;
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 (demandedFormat === 3) {
if ( isArray(propertyValue)) {
data[name+'@odata.type'] = '#' + property.type;
for ( var i = 0; i < propertyValue.length; i++) {
jsonLightReadComplexObjectNew(propertyValue[0], property,baseURI,model,demandedFormat, recognizeDates);
}
} else if (isObject(propertyValue) && (propertyValue!= null)) {
jsonLightReadComplexObjectNew(propertyValue, property,baseURI,model,demandedFormat, recognizeDates);
} else {
data[name+'@odata.type'] = '#' + property.type;
}
} else {
}
}
}
return data;
};
var jsonLightReadObject = function (data, objectInfo, baseURI, model, recognizeDates) {
/// <summary>Converts a JSON light entry or complex type object into its library representation.</summary>
/// <param name="data" type="Object">JSON light entry or complex type object to convert.</param>
/// <param name="objectInfo" type="Object">Information about the entry or complex.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns type="Object">Entry or complex type object.</param>
objectInfo = objectInfo || {};
var actualType = data[typeAnnotation] || objectInfo.type || null;
var dataModel = lookupEntityType(actualType, model);
var isEntry = true;
if (!dataModel) {
isEntry = false;
dataModel = lookupComplexType(actualType, model);
}
var metadata = { type: actualType };
var obj = { __metadata: metadata };
var propertiesMetadata = {};
var baseTypeModel;
if (isEntry && dataModel && objectInfo.entitySet && objectInfo.contentTypeOdata === "minimalmetadata") {
var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata"));
baseTypeModel = null; // check if the key model is in a parent type.
if (!dataModel.key) {
baseTypeModel = dataModel;
}
while (!!baseTypeModel && !baseTypeModel.key && baseTypeModel.baseType) {
baseTypeModel = lookupEntityType(baseTypeModel.baseType, model);
}
if (dataModel.key || (!!baseTypeModel && baseTypeModel.key)) {
var entryKey;
if (dataModel.key) {
entryKey = jsonLightGetEntryKey(data, dataModel);
} else {
entryKey = jsonLightGetEntryKey(data, baseTypeModel);
}
if (entryKey) {
var entryInfo = {
key: entryKey,
entitySet: objectInfo.entitySet,
functionImport: objectInfo.functionImport,
containerName: objectInfo.containerName
};
jsonLightComputeUrisIfMissing(data, entryInfo, actualType, serviceURI, dataModel, baseTypeModel);
}
}
}
for (var name in data) {
if (name.indexOf("#") === 0) {
// This is an advertised function or action.
jsonLightReadAdvertisedFunctionOrAction(name.substring(1), data[name], obj, baseURI, model);
} else {
// Is name NOT an annotation?
if (name.indexOf(".") === -1) {
if (!metadata.properties) {
metadata.properties = propertiesMetadata;
}
var propertyValue = data[name];
var propertyModel = propertyModel = jsonLightDataItemModel(name, dataModel);
baseTypeModel = dataModel;
while (!!dataModel && propertyModel === null && baseTypeModel.baseType) {
baseTypeModel = lookupEntityType(baseTypeModel.baseType, model);
propertyModel = propertyModel = jsonLightDataItemModel(name, baseTypeModel);
}
var isNavigationProperty = jsonLightIsNavigationProperty(name, data, propertyModel);
var propertyType = jsonLightDataItemType(name, propertyValue, data, propertyModel, model);
var propertyMetadata = propertiesMetadata[name] = propertiesMetadata[name] || { type: propertyType };
if (isNavigationProperty) {
var propertyInfo = {};
if (objectInfo.entitySet !== undefined) {
var navigationPropertyEntitySetName = lookupNavigationPropertyEntitySet(propertyModel, objectInfo.entitySet.name, model);
propertyInfo = getEntitySetInfo(navigationPropertyEntitySetName, model);
}
propertyInfo.contentTypeOdata = objectInfo.contentTypeOdata;
propertyInfo.kind = objectInfo.kind;
propertyInfo.type = propertyType;
obj[name] = jsonLightReadNavigationPropertyValue(propertyValue, propertyInfo, baseURI, model, recognizeDates);
} else {
obj[name] = jsonLightReadDataItemValue(propertyValue, propertyType, propertyMetadata, baseURI, propertyModel, model, recognizeDates);
}
}
}
}
return jsonLightReadDataAnnotations(data, obj, baseURI, dataModel, model);
};
var jsonLightReadAdvertisedFunctionOrAction = function (name, value, obj, baseURI, model) {
/// <summary>Converts a JSON light advertised action or function object into its library representation.</summary>
/// <param name="name" type="String">Advertised action or function name.</param>
/// <param name="value">Advertised action or function value.</param>
/// <param name="obj" type="Object">Object that will the converted value of the advertised action or function.</param>
/// <param name="baseURI" type="String">Base URI for normalizing the action's or function's relative URIs.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <remarks>
/// Actions and functions have the same representation in json light, so to disambiguate them the function uses
/// the model object. If available, the function will look for the functionImport object that describes the
/// the action or the function. If for whatever reason the functionImport can't be retrieved from the model (like
/// there is no model available or there is no functionImport within the model), then the value is going to be treated
/// as an advertised action and stored under obj.__metadata.actions.
/// </remarks>
if (!name || !isArray(value) && !isComplex(value)) {
return;
}
var isFunction = false;
var nsEnd = name.lastIndexOf(".");
var simpleName = name.substring(nsEnd + 1);
var containerName = (nsEnd > -1) ? name.substring(0, nsEnd) : "";
var container = (simpleName === name || containerName.indexOf(".") === -1) ?
lookupDefaultEntityContainer(model) :
lookupEntityContainer(containerName, model);
if (container) {
var functionImport = lookupFunctionImport(container.functionImport, simpleName);
if (functionImport && !!functionImport.isSideEffecting) {
isFunction = !parseBool(functionImport.isSideEffecting);
}
}
var metadata = obj.__metadata;
var targetName = isFunction ? "functions" : "actions";
var metadataURI = normalizeURI(name, baseURI);
var items = (isArray(value)) ? value : [value];
var i, len;
for (i = 0, len = items.length; i < len; i++) {
var item = items[i];
if (item) {
var targetCollection = metadata[targetName] = metadata[targetName] || [];
var actionOrFunction = { metadata: metadataURI, title: item.title, target: normalizeURI(item.target, baseURI) };
targetCollection.push(actionOrFunction);
}
}
};
var jsonLightReadFeedNew = function (data, feedInfo, baseURI, model, demandedFormat,recognizeDates) {
var entries = [];
var items = data.value;
for (i = 0, len = items.length; i < len; i++) {
//TODO SK check if items[i] has @odata.type and use this type instead of feedinfo
if ( items[i]['@odata.type'] !== undefined) {
var typeName = items[i]['@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 = jsonLightReadObjectNew(items[i], entryInfo, baseURI, model, demandedFormat,recognizeDates);
} else {
entry = jsonLightReadObjectNew(items[i], feedInfo, baseURI, model, demandedFormat,recognizeDates);
}
entries.push(entry);
}
data.value = entries;
return data;
};
var jsonLightReadFeed = function (data, feedInfo, baseURI, model, recognizeDates) {
/// <summary>Converts a JSON light feed or top level collection property object into its library representation.</summary>
/// <param name="data" type="Object">JSON light feed object to convert.</param>
/// <param name="typeName" type="String">Type name of the feed or collection items.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns type="Object">Feed or top level collection object.</param>
var items = isArray(data) ? data : data.value;
var entries = [];
var i, len, entry;
for (i = 0, len = items.length; i < len; i++) {
entry = jsonLightReadObject(items[i], feedInfo, baseURI, model, recognizeDates);
entries.push(entry);
}
var feed = { results: entries };
if (isComplex(data)) {
for (var name in data) {
if (name.indexOf("#") === 0) {
// This is an advertised function or action.
feed.__metadata = feed.__metadata || {};
jsonLightReadAdvertisedFunctionOrAction(name.substring(1), data[name], feed, baseURI, model);
}
}
feed = jsonLightReadDataAnnotations(data, feed, baseURI);
}
return feed;
};
var jsonLightGetEntryKey = function (data, entityModel) {
/// <summary>Gets the key of an entry.</summary>
/// <param name="data" type="Object">JSON light entry.</param>
/// <param name="entityModel" type="String">Object describing the entry Model</param>
/// <returns type="string">Entry instance key.</returns>
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;
};
var jsonLightComputeUrisIfMissing = function (data, entryInfo, actualType, serviceURI, entityModel, baseTypeModel) {
/// <summary>Compute the URI according to OData conventions if it doesn't exist</summary>
/// <param name="data" type="Object">JSON light entry.</param>
/// <param name="entryInfo" type="Object">Information about the entry includes type, key, entitySet and entityContainerName.</param>
/// <param name="actualType" type="String">Type of the entry</param>
/// <param name="serviceURI" type="String">Base URI the service.</param>
/// <param name="entityModel" type="Object">Object describing an OData conceptual schema of the entry.</param>
/// <param name="baseTypeModel" type="Object" optional="true">Object escribing an OData conceptual schema of the baseType if it exists.</param>
var lastIdSegment = data[jsonLightAnnotations.id] || data[jsonLightAnnotations.read] || data[jsonLightAnnotations.edit] || entryInfo.entitySet.name + entryInfo.key;
data[jsonLightAnnotations.id] = serviceURI + lastIdSegment;
if (!data[jsonLightAnnotations.edit]) {
data[jsonLightAnnotations.edit] = entryInfo.entitySet.name + entryInfo.key;
if (entryInfo.entitySet.entityType != actualType) {
data[jsonLightAnnotations.edit] += "/" + actualType;
}
}
data[jsonLightAnnotations.read] = data[jsonLightAnnotations.read] || data[jsonLightAnnotations.edit];
if (!data[jsonLightAnnotations.etag]) {
var etag = jsonLightComputeETag(data, entityModel, baseTypeModel);
if (!!etag) {
data[jsonLightAnnotations.etag] = etag;
}
}
jsonLightComputeStreamLinks(data, entityModel, baseTypeModel);
jsonLightComputeNavigationAndAssociationProperties(data, entityModel, baseTypeModel);
jsonLightComputeFunctionImports(data, entryInfo);
};
var jsonLightComputeETag = function (data, entityModel, baseTypeModel) {
/// <summary>Computes the etag of an entry</summary>
/// <param name="data" type="Object">JSON light entry.</param>
/// <param name="entryInfo" type="Object">Object describing the entry model.</param>
/// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
/// <returns type="string">Etag value</returns>
var etag = "";
var propertyModel;
for (var i = 0; entityModel.property && i < entityModel.property.length; i++) {
propertyModel = entityModel.property[i];
etag = jsonLightAppendValueToEtag(data, etag, propertyModel);
}
if (baseTypeModel) {
for (i = 0; baseTypeModel.property && i < baseTypeModel.property.length; i++) {
propertyModel = baseTypeModel.property[i];
etag = jsonLightAppendValueToEtag(data, etag, propertyModel);
}
}
if (etag.length > 0) {
return etag + "\"";
}
return null;
};
var jsonLightAppendValueToEtag = function (data, etag, propertyModel) {
/// <summary>Adds a propery value to the etag after formatting.</summary>
/// <param name="data" type="Object">JSON light entry.</param>
/// <param name="etag" type="Object">value of the etag.</param>
/// <param name="propertyModel" type="Object">Object describing an OData conceptual schema of the property.</param>
/// <returns type="string">Etag value</returns>
if (propertyModel.concurrencyMode == "Fixed") {
if (etag.length > 0) {
etag += ",";
} else {
etag += "W/\"";
}
if (data[propertyModel.name] !== null) {
etag += formatLiteral(data[propertyModel.name], propertyModel.type);
} else {
etag += "null";
}
}
return etag;
};
var jsonLightComputeNavigationAndAssociationProperties = function (data, entityModel, baseTypeModel) {
/// <summary>Adds navigation links to the entry metadata</summary>
/// <param name="data" type="Object">JSON light entry.</param>
/// <param name="entityModel" type="Object">Object describing the entry model.</param>
/// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
var navigationLinkAnnotation = "@odata.navigationLinkUrl";
var associationLinkAnnotation = "@odata.associationLinkUrl";
var navigationPropertyName, navigationPropertyAnnotation, associationPropertyAnnotation;
for (var i = 0; entityModel.navigationProperty && i < entityModel.navigationProperty.length; i++) {
navigationPropertyName = entityModel.navigationProperty[i].name;
navigationPropertyAnnotation = navigationPropertyName + navigationLinkAnnotation;
if (data[navigationPropertyAnnotation] === undefined) {
data[navigationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/" + encodeURIComponent(navigationPropertyName);
}
associationPropertyAnnotation = navigationPropertyName + associationLinkAnnotation;
if (data[associationPropertyAnnotation] === undefined) {
data[associationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/$links/" + encodeURIComponent(navigationPropertyName);
}
}
if (baseTypeModel && baseTypeModel.navigationProperty) {
for (i = 0; i < baseTypeModel.navigationProperty.length; i++) {
navigationPropertyName = baseTypeModel.navigationProperty[i].name;
navigationPropertyAnnotation = navigationPropertyName + navigationLinkAnnotation;
if (data[navigationPropertyAnnotation] === undefined) {
data[navigationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/" + encodeURIComponent(navigationPropertyName);
}
associationPropertyAnnotation = navigationPropertyName + associationLinkAnnotation;
if (data[associationPropertyAnnotation] === undefined) {
data[associationPropertyAnnotation] = data[jsonLightAnnotations.edit] + "/$links/" + encodeURIComponent(navigationPropertyName);
}
}
}
};
var formatLiteral = function (value, type) {
/// <summary>Formats a value according to Uri literal format</summary>
/// <param name="value">Value to be formatted.</param>
/// <param name="type">Edm type of the value</param>
/// <returns type="string">Value after formatting</returns>
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;
}
};
var formatRowLiteral = function (value, type) {
switch (type) {
case "Edm.Binary":
return convertByteArrayToHexString(value);
default:
return value;
}
};
var jsonLightComputeFunctionImports = function (data, entryInfo) {
/// <summary>Adds functions and actions links to the entry metadata</summary>
/// <param name="entry" type="Object">JSON light entry.</param>
/// <param name="entityInfo" type="Object">Object describing the entry</param>
var functionImport = entryInfo.functionImport || [];
for (var i = 0; i < functionImport.length; i++) {
if (functionImport[i].isBindable && functionImport[i].parameter[0] && functionImport[i].parameter[0].type == entryInfo.entitySet.entityType) {
var functionImportAnnotation = "#" + entryInfo.containerName + "." + functionImport[i].name;
if (data[functionImportAnnotation] == undefined) {
data[functionImportAnnotation] = {
title: functionImport[i].name,
target: data[jsonLightAnnotations.edit] + "/" + functionImport[i].name
};
}
}
}
};
var jsonLightComputeStreamLinks = function (data, entityModel, baseTypeModel) {
/// <summary>Adds stream links to the entry metadata</summary>
/// <param name="data" type="Object">JSON light entry.</param>
/// <param name="entityModel" type="Object">Object describing the entry model.</param>
/// <param name="baseTypeModel" type="Object" optional="true">Object describing an OData conceptual schema of the baseType if it exists.</param>
if (entityModel.hasStream || (baseTypeModel && baseTypeModel.hasStream)) {
data[jsonLightAnnotations.mediaEdit] = data[jsonLightAnnotations.mediaEdit] || data[jsonLightAnnotations.mediaEdit] + "/$value";
data[jsonLightAnnotations.mediaRead] = data[jsonLightAnnotations.mediaRead] || data[jsonLightAnnotations.mediaEdit];
}
};
/*
var jsonLightReadTopPrimitiveProperty = function (data, typeName, baseURI, recognizeDates) {
/// <summary>Converts a JSON light top level primitive property object into its library representation.</summary>
/// <param name="data" type="Object">JSON light feed object to convert.</param>
/// <param name="typeName" type="String">Type name of the primitive property.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns type="Object">Top level primitive property object.</param>
var metadata = { type: typeName };
var value = jsonLightReadDataItemValue(data.value, typeName, metadata, baseURI, null, null, recognizeDates);
return jsonLightReadDataAnnotations(data, { __metadata: metadata, value: value }, baseURI);
};*/
/*
var jsonLightReadTopCollectionProperty = function (data, typeName, baseURI, model, recognizeDates) {
/// <summary>Converts a JSON light top level collection property object into its library representation.</summary>
/// <param name="data" type="Object">JSON light feed object to convert.</param>
/// <param name="typeName" type="String">Type name of the collection property.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
/// <param name="recognizeDates" type="Boolean" optional="true">Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.</param>
/// <returns type="Object">Top level collection property object.</param>
var propertyMetadata = {};
var value = jsonLightReadCollectionPropertyValue(data.value, typeName, propertyMetadata, baseURI, model, recognizeDates);
extend(value.__metadata, propertyMetadata);
return jsonLightReadDataAnnotations(data, value, baseURI);
};*/
/*
var jsonLightReadLinksDocument = function (data, baseURI) {
/// <summary>Converts a JSON light links collection object to its library representation.</summary>
/// <param name="data" type="Object">JSON light link object to convert.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <returns type="Object">Links collection object.</param>
var items = data.value;
if (!isArray(items)) {
return jsonLightReadLink(data, baseURI);
}
var results = [];
var i, len;
for (i = 0, len = items.length; i < len; i++) {
results.push(jsonLightReadLink(items[i], baseURI));
}
var links = { results: results };
return jsonLightReadDataAnnotations(data, links, baseURI);
};*/
/*
var jsonLightReadLink = function (data, baseURI) {
/// <summary>Converts a JSON light link object to its library representation.</summary>
/// <param name="data" type="Object">JSON light link object to convert.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <returns type="Object">Link object.</param>
var link = { uri: normalizeURI(data.url, baseURI) };
link = jsonLightReadDataAnnotations(data, link, baseURI);
var metadata = link.__metadata || {};
var metadataProperties = metadata.properties || {};
jsonLightRemoveTypePropertyMetadata(metadataProperties.url);
renameProperty(metadataProperties, "url", "uri");
return link;
};*/
/*
var jsonLightRemoveTypePropertyMetadata = function (propertyMetadata) {
/// <summary>Removes the type property from a property metadata object.</summary>
/// <param name="propertyMetadata" type="Object">Property metadata object.</param>
if (propertyMetadata) {
delete propertyMetadata.type;
}
};*/
/*
var jsonLightReadSvcDocument = function (data, baseURI) {
/// <summary>Converts a JSON light service document object to its library representation.</summary>
/// <param name="data" type="Object">JSON light service document object to convert.</param>
/// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the payload.</param>
/// <returns type="Object">Link object.</param>
var items = data.value;
var collections = [];
var workspace = jsonLightReadDataAnnotations(data, { collections: collections }, baseURI);
var metadata = workspace.__metadata || {};
var metadataProperties = metadata.properties || {};
jsonLightRemoveTypePropertyMetadata(metadataProperties.value);
renameProperty(metadataProperties, "value", "collections");
var i, len;
for (i = 0, len = items.length; i < len; i++) {
var item = items[i];
var collection = { title: item.name, href: normalizeURI(item.url, baseURI) };
collection = jsonLightReadDataAnnotations(item, collection, baseURI);
metadata = collection.__metadata || {};
metadataProperties = metadata.properties || {};
jsonLightRemoveTypePropertyMetadata(metadataProperties.name);
jsonLightRemoveTypePropertyMetadata(metadataProperties.url);
renameProperty(metadataProperties, "name", "title");
renameProperty(metadataProperties, "url", "href");
collections.push(collection);
}
return { workspaces: [workspace] };
};*/
var jsonLightSerializableMetadata = ["@odata.type", "@odata.etag", "@odata.mediaEditLink", "@odata.mediaReadLink", "@odata.mediaContentType", "@odata.mediaEtag"];
var formatJsonLightRequestPayload = function (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] = formatJsonLightRequestPayload(data[i]);
}
return newArrayData;
}
var newdata = {};
for (var property in data) {
if (isJsonLightSerializableProperty(property)) {
newdata[property] = formatJsonLightRequestPayload(data[property]);
}
}
return newdata;
};
var isJsonLightSerializableProperty = function (property) {
if (!property) {
return false;
}
if (property.indexOf("@odata.") == -1) {
return true;
}
var i, len;
for (i = 0, len = jsonLightSerializableMetadata.length; i < len; i++) {
var name = jsonLightSerializableMetadata[i];
if (property.indexOf(name) != -1) {
return true;
}
}
return false;
};
var formatJsonLight = function (obj, context) {
/// <summary>Converts an object in the library's internal representation to its json light representation.</summary>
/// <param name="obj" type="Object">Object the library's internal representation.</param>
/// <param name="context" type="Object">Object with the serialization context.</param>
/// <returns type="Object">Object in its json light representation.</returns>
// Regular expression used to test that the uri is for a $links document.
var linksUriRE = /\/\$links\//;
var data = {};
var metadata = obj.__metadata;
var islinks = context && linksUriRE.test(context.request.requestUri);
formatJsonLightData(obj, (metadata && metadata.properties), data, islinks);
return data;
};
var formatJsonLightMetadata = function (metadata, data) {
/// <summary>Formats an object's metadata into the appropriate json light annotations and saves them to data.</summary>
/// <param name="obj" type="Object">Object whose metadata is going to be formatted as annotations.</param>
/// <param name="data" type="Object">Object on which the annotations are going to be stored.</param>
if (metadata) {
var i, len;
for (i = 0, len = jsonLightSerializableMetadata.length; i < len; i++) {
// There is only a subset of metadata values that are interesting during update requests.
var name = jsonLightSerializableMetadata[i];
var qName = odataAnnotationPrefix + (jsonLightNameMap[name] || name);
formatJsonLightAnnotation(qName, null, metadata[name], data);
}
}
};
var formatJsonLightData = function (obj, pMetadata, data, isLinks) {
/// <summary>Formats an object's data into the appropriate json light values and saves them to data.</summary>
/// <param name="obj" type="Object">Object whose data is going to be formatted.</param>
/// <param name="pMetadata" type="Object">Object that contains metadata for the properties that are being formatted.</param>
/// <param name="data" type="Object">Object on which the formatted values are going to be stored.</param>
/// <param name="isLinks" type="Boolean">True if a links document is being formatted. False otherwise.</param>
for (var key in obj) {
var value = obj[key];
if (key === "__metadata") {
// key is the object metadata.
formatJsonLightMetadata(value, data);
} else if (key.indexOf(".") === -1) {
// key is an regular property or array element.
if (isLinks && key === "uri") {
formatJsonLightEntityLink(value, data);
} else {
formatJsonLightProperty(key, value, pMetadata, data, isLinks);
}
} else {
data[key] = value;
}
}
};
var MyDateTime = function(value) {
this.value = value;
}
MyDateTime.prototype.getAsDateObject = function () { return { value : this.value }};
var formatJsonLightProperty = function (name, value, pMetadata, data) {
/// <summary>Formats an object's value identified by name to its json light representation and saves it to data.</summary>
/// <param name="name" type="String">Property name.</param>
/// <param name="value">Property value.</param>
/// <param name="pMetadata" type="Object">Object that contains metadata for the property that is being formatted.</param>
/// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
// Get property type from property metadata
var propertyMetadata = pMetadata && pMetadata[name] || { properties: undefined, type: undefined };
var typeName = dataItemTypeName(value, propertyMetadata);
if (isPrimitive(value) || !value) {
// It is a primitive value then.
formatJsonLightAnnotation(typeAnnotation, name, typeName, data);
/*TODO*//*check the typename here*/
if ( typeName === 'Edm.DateTime') {
data[name] = new MyDateTime(value);
} else if ( typeName === 'Edm.DateTimeOffset') {
data[name] = new MyDateTime(value);
} else {
data[name] = value;
}
return;
}
if (isFeed(value, typeName) || isEntry(value)) {
formatJsonLightInlineProperty(name, value, data);
return;
}
if (!typeName && isDeferred(value)) {
// It is really a deferred property.
formatJsonLightDeferredProperty(name, value, data);
return;
}
if (isCollection(value, typeName)) {
// The thing is a collection, format it as one.
if (getCollectionType(typeName)) {
formatJsonLightAnnotation(typeAnnotation, name, typeName, data);
}
formatJsonLightCollectionProperty(name, value, data);
return;
}
djsassert(isComplex(value), "formatJsonLightProperty - Value is not a complex type value");
// Format the complex property value in a new object in data[name].
data[name] = {};
formatJsonLightAnnotation(typeAnnotation, null, typeName, data[name]);
formatJsonLightData(value, propertyMetadata.properties, data[name]);
};
var formatJsonLightEntityLink = function (value, data) {
/// <summary>Formats an entity link in a $links document and saves it into data.</summary>
/// <param name="value" type="String">Entity link value.</summary>
/// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
data.url = value;
};
var formatJsonLightDeferredProperty = function (name, value, data) {
/// <summary>Formats the object value's identified by name as an odata.navigalinkurl annotation and saves it to data.</summary>
/// <param name="name" type="String">Name of the deferred property to be formatted.</param>
/// <param name="value" type="Object">Deferred property value to be formatted.</param>
/// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
formatJsonLightAnnotation(navUrlAnnotation, name, value.__deferred.uri, data);
};
var formatJsonLightCollectionProperty = function (name, value, data) {
/// <summary>Formats a collection property in obj identified by name as a json light collection property and saves it to data.</summary>
/// <param name="name" type="String">Name of the collection property to be formatted.</param>
/// <param name="value" type="Object">Collection property value to be formatted.</param>
/// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
data[name] = [];
var items = isArray(value) ? value : value.results;
formatJsonLightData(items, null, data[name]);
};
var formatJsonLightInlineProperty = function (name, value, data) {
/// <summary>Formats an inline feed or entry property in obj identified by name as a json light value and saves it to data.</summary>
/// <param name="name" type="String">Name of the inline feed or entry property to be formatted.</param>
/// <param name="value" type="Object or Array">Value of the inline feed or entry property.</param>
/// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
if (isFeed(value)) {
data[name] = [];
// Format each of the inline feed entries
var entries = isArray(value) ? value : value.results;
var i, len;
for (i = 0, len = entries.length; i < len; i++) {
formatJsonLightInlineEntry(name, entries[i], true, data);
}
return;
}
formatJsonLightInlineEntry(name, value, false, data);
};
var formatJsonLightInlineEntry = function (name, value, inFeed, data) {
/// <summary>Formats an inline entry value in the property identified by name as a json light value and saves it to data.</summary>
/// <param name="name" type="String">Name of the inline feed or entry property that owns the entry formatted.</param>
/// <param name="value" type="Object">Inline entry value to be formatted.</param>
/// <param name="inFeed" type="Boolean">True if the entry is in an inline feed; false otherwise.
/// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
// This might be a bind instead of a deep insert.
var uri = value.__metadata && value.__metadata.uri;
if (uri) {
formatJsonLightBinding(name, uri, inFeed, data);
return;
}
var entry = formatJsonLight(value);
if (inFeed) {
data[name].push(entry);
return;
}
data[name] = entry;
};
var formatJsonLightBinding = function (name, uri, inFeed, data) {
/// <summary>Formats an entry binding in the inline property in obj identified by name as an odata.bind annotation and saves it to data.</summary>
/// <param name="name" type="String">Name of the inline property that has the binding to be formated.</param>
/// <param name="uri" type="String">Uri to the bound entry.</param>
/// <param name="inFeed" type="Boolean">True if the binding is in an inline feed; false otherwise.
/// <param name="data" type="Object">Object on which the formatted value is going to be stored.</param>
var bindingName = name + bindAnnotation;
if (inFeed) {
// The binding is inside an inline feed, so merge it with whatever other bindings already exist in data.
data[bindingName] = data[bindingName] || [];
data[bindingName].push(uri);
return;
}
// The binding is on an inline entry; it can be safely overwritten.
data[bindingName] = uri;
};
var formatJsonLightAnnotation = function (qName, target, value, data) {
/// <summary>Formats a value as a json light annotation and stores it in data</summary>
/// <param name="qName" type="String">Qualified name of the annotation.</param>
/// <param name="target" type="String">Name of the property that the metadata value targets.</param>
/// <param name="value">Annotation value.</param>
/// <param name="data" type="Object">Object on which the annotation is going to be stored.</param>
if (value !== undefined) {
if(target) {
data[target + "@" + qName] = value;
}
else {
data[qName] = value;
}
}
};
// DATAJS INTERNAL START
//exports.jsonLightPayloadInfo = jsonLightPayloadInfo;
//exports.jsonLightReadPayload = jsonLightReadPayload;
exports.formatJsonLight = formatJsonLight;
exports.formatJsonLightRequestPayload = formatJsonLightRequestPayload;
// DATAJS INTERNAL END