You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by bi...@apache.org on 2014/03/26 05:23:27 UTC
[10/15] This change set contains the odata javascript library V3. The
version number is 1.1.2
http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/src/odata-json-light.js
----------------------------------------------------------------------
diff --git a/JSLib/src/odata-json-light.js b/JSLib/src/odata-json-light.js
new file mode 100644
index 0000000..9a10601
--- /dev/null
+++ b/JSLib/src/odata-json-light.js
@@ -0,0 +1,1391 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-json-light.js
+
+(function (window, undefined) {
+
+ var datajs = window.datajs || {};
+ var odata = window.OData || {};
+
+ // Imports
+
+ var assigned = datajs.assigned;
+ var djsassert = datajs.djsassert;
+ var extend = datajs.extend;
+ var getURIInfo = datajs.getURIInfo;
+ var isArray = datajs.isArray;
+ var isDate = datajs.isDate;
+ var normalizeURI = datajs.normalizeURI;
+ var renameProperty = datajs.renameProperty;
+ var undefinedDefault = datajs.undefinedDefault;
+ var convertByteArrayToHexString = datajs.convertByteArrayToHexString;
+
+ var dataItemTypeName = odata.dataItemTypeName;
+ var EDM_DATETIME = odata.EDM_DATETIME;
+ var EDM_DATETIMEOFFSET = odata.EDM_DATETIMEOFFSET;
+ var EDM_TIME = odata.EDM_TIME;
+ var getCollectionType = odata.getCollectionType;
+ var isCollection = odata.isCollection;
+ var isCollectionType = odata.isCollectionType;
+ var isComplex = odata.isComplex;
+ var isDeferred = odata.isDeferred;
+ var isFeed = odata.isFeed;
+ var isEntry = odata.isEntry;
+ var isGeographyEdmType = odata.isGeographyEdmType;
+ var isGeometryEdmType = odata.isGeometryEdmType;
+ var isPrimitiveEdmType = odata.isPrimitiveEdmType;
+ var isPrimitive = odata.isPrimitive;
+ var lookupComplexType = odata.lookupComplexType;
+ var lookupDefaultEntityContainer = odata.lookupDefaultEntityContainer;
+ var lookupEntityContainer = odata.lookupEntityContainer;
+ var lookupEntitySet = odata.lookupEntitySet;
+ var lookupEntityType = odata.lookupEntityType;
+ var lookupFunctionImport = odata.lookupFunctionImport;
+ var lookupNavigationPropertyType = odata.lookupNavigationPropertyType;
+ var getEntitySetInfo = odata.getEntitySetInfo;
+ var lookupNavigationPropertyEntitySet = odata.lookupNavigationPropertyEntitySet;
+ var lookupProperty = odata.lookupProperty;
+ var parseBool = odata.parseBool;
+ var parseDateTime = odata.parseDateTime;
+ var parseDateTimeOffset = odata.parseDateTimeOffset;
+ var parseDuration = odata.parseDuration;
+
+ // CONTENT START
+
+ var PAYLOADTYPE_OBJECT = "o";
+ var PAYLOADTYPE_FEED = "f";
+ var PAYLOADTYPE_PRIMITIVE = "p";
+ var PAYLOADTYPE_COLLECTION = "c";
+ var PAYLOADTYPE_SVCDOC = "s";
+ var PAYLOADTYPE_LINKS = "l";
+
+ var odataNs = "odata";
+ var odataAnnotationPrefix = odataNs + ".";
+
+ var bindAnnotation = "@" + odataAnnotationPrefix + "bind";
+ var metadataAnnotation = odataAnnotationPrefix + "metadata";
+ 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;
+ };
+
+ 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 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 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.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 jsonLightMakePayloadInfo = function (kind, type) {
+ /// <summary>Creates an object containing information for the json light payload.</summary>
+ /// <param name="kind" type="String">JSON light payload kind, one of the PAYLOADTYPE_XXX constant values.</param>
+ /// <param name="typeName" type="String">Type name of the JSON light payload.</param>
+ /// <returns type="Object">Object with kind and type fields.</returns>
+
+ /// <field name="kind" type="String">Kind of the JSON light payload. One of the PAYLOADTYPE_XXX constant values.</field>
+ /// <field name="type" type="String">Data type of the JSON light payload.</field>
+
+ return { kind: kind, type: type || null };
+ };
+
+ var jsonLightPayloadInfo = function (data, model, inferFeedAsComplexType) {
+ /// <summary>Infers the information describing the JSON light payload from its metadata annotation, structure, and data model.</summary>
+ /// <param name="data" type="Object">Json light response payload object.</param>
+ /// <param name="model" type="Object">Object describing an OData conceptual schema.</param>
+ /// <param name="inferFeedAsComplexType" type="Boolean">True if a JSON light payload that looks like a feed should be treated as a complex type property instead.</param>
+ /// <remarks>
+ /// 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 light payload.
+ /// </remarks>
+ /// <returns type="Object">
+ /// Object with kind and type fields. Null if there is no metadata annotation or the payload info cannot be obtained..
+ /// </returns>
+
+ var metadataUri = data[metadataAnnotation];
+ if (!metadataUri || typeof metadataUri !== "string") {
+ return null;
+ }
+
+ var fragmentStart = metadataUri.lastIndexOf("#");
+ if (fragmentStart === -1) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_SVCDOC);
+ }
+
+ var elementStart = metadataUri.indexOf("@Element", fragmentStart);
+ var fragmentEnd = elementStart - 1;
+
+ if (fragmentEnd < 0) {
+ fragmentEnd = metadataUri.indexOf("?", fragmentStart);
+ if (fragmentEnd === -1) {
+ fragmentEnd = metadataUri.length;
+ }
+ }
+
+ var fragment = metadataUri.substring(fragmentStart + 1, fragmentEnd);
+ if (fragment.indexOf("/$links/") > 0) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_LINKS);
+ }
+
+ var fragmentParts = fragment.split("/");
+ if (fragmentParts.length >= 0) {
+ var qualifiedName = fragmentParts[0];
+ var typeCast = fragmentParts[1];
+
+ if (jsonLightIsPrimitiveType(qualifiedName)) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_PRIMITIVE, qualifiedName);
+ }
+
+ if (isCollectionType(qualifiedName)) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_COLLECTION, qualifiedName);
+ }
+
+ var entityType = typeCast;
+ var entitySet, functionImport, containerName;
+ if (!typeCast) {
+ var nsEnd = qualifiedName.lastIndexOf(".");
+ var simpleName = qualifiedName.substring(nsEnd + 1);
+ var container = (simpleName === qualifiedName) ?
+ lookupDefaultEntityContainer(model) :
+ lookupEntityContainer(qualifiedName.substring(0, nsEnd), model);
+
+ if (container) {
+ entitySet = lookupEntitySet(container.entitySet, simpleName);
+ functionImport = container.functionImport;
+ containerName = container.name;
+ entityType = !!entitySet ? entitySet.entityType : null;
+ }
+ }
+
+ var info;
+ if (elementStart > 0) {
+ info = jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, entityType);
+ info.entitySet = entitySet;
+ info.functionImport = functionImport;
+ info.containerName = containerName;
+ return info;
+ }
+
+ if (entityType) {
+ info = jsonLightMakePayloadInfo(PAYLOADTYPE_FEED, entityType);
+ info.entitySet = entitySet;
+ info.functionImport = functionImport;
+ info.containerName = containerName;
+ return info;
+ }
+
+ if (isArray(data.value) && !lookupComplexType(qualifiedName, model)) {
+ var item = data.value[0];
+ if (!isPrimitive(item)) {
+ if (jsonLightIsEntry(item) || !inferFeedAsComplexType) {
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_FEED, null);
+ }
+ }
+ }
+
+ return jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, qualifiedName);
+ }
+
+ return null;
+ };
+
+ var jsonLightReadPayload = function (data, model, recognizeDates, inferFeedAsComplexType, contentTypeOdata) {
+ /// <summary>Converts a JSON light response payload object into its library's internal representation.</summary>
+ /// <param name="data" type="Object">Json light response payload object.</param>
+ /// <param name="model" type="Object">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>
+ /// <param name="inferFeedAsComplexType" type="Boolean">True if a JSON light payload that looks like a feed should be reported as a complex type property instead.</param>
+ /// <param name="contentTypeOdata" type="string">Includes the type of json ( minimalmetadata, fullmetadata .. etc )</param>
+ /// <returns type="Object">Object in the library's representation.</returns>
+
+ if (!isComplex(data)) {
+ return data;
+ }
+
+ contentTypeOdata = contentTypeOdata || "minimalmetadata";
+ var baseURI = data[metadataAnnotation];
+ var payloadInfo = jsonLightPayloadInfo(data, model, inferFeedAsComplexType);
+ if (assigned(payloadInfo)) {
+ payloadInfo.contentTypeOdata = contentTypeOdata;
+ }
+ var typeName = null;
+ if (payloadInfo) {
+ delete data[metadataAnnotation];
+
+ typeName = payloadInfo.type;
+ switch (payloadInfo.kind) {
+ case PAYLOADTYPE_FEED:
+ return jsonLightReadFeed(data, payloadInfo, baseURI, model, recognizeDates);
+ case PAYLOADTYPE_COLLECTION:
+ return jsonLightReadTopCollectionProperty(data, typeName, baseURI, model, recognizeDates);
+ case PAYLOADTYPE_PRIMITIVE:
+ return jsonLightReadTopPrimitiveProperty(data, typeName, baseURI, recognizeDates);
+ case PAYLOADTYPE_SVCDOC:
+ return jsonLightReadSvcDocument(data, baseURI);
+ case PAYLOADTYPE_LINKS:
+ return jsonLightReadLinksDocument(data, baseURI);
+ }
+ }
+ return jsonLightReadObject(data, payloadInfo, baseURI, model, recognizeDates);
+ };
+
+ var jsonLightSerializableMetadata = ["type", "etag", "media_src", "edit_media", "content_type", "media_etag"];
+
+ 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 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);
+ 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
+ odata.jsonLightReadPayload = jsonLightReadPayload;
+ odata.formatJsonLight = formatJsonLight;
+ // DATAJS INTERNAL END
+
+ // CONTENT END
+})(this);
+
+
+