| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <title>JSDoc: Source: odata/json.js</title> |
| |
| <script src="scripts/prettify/prettify.js"> </script> |
| <script src="scripts/prettify/lang-css.js"> </script> |
| <!--[if lt IE 9]> |
| <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> |
| <![endif]--> |
| <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> |
| <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> |
| </head> |
| |
| <body> |
| |
| <div id="main"> |
| |
| <h1 class="page-title">Source: odata/json.js</h1> |
| |
| |
| |
| |
| |
| <section> |
| <article> |
| <pre class="prettyprint source"><code>/*
|
| * Licensed to the Apache Software Foundation (ASF) under one
|
| * or more contributor license agreements. See the NOTICE file
|
| * distributed with this work for additional information
|
| * regarding copyright ownership. The ASF licenses this file
|
| * to you under the Apache License, Version 2.0 (the
|
| * "License"); you may not use this file except in compliance
|
| * with the License. You may obtain a copy of the License at
|
| *
|
| * http://www.apache.org/licenses/LICENSE-2.0
|
| *
|
| * Unless required by applicable law or agreed to in writing,
|
| * software distributed under the License is distributed on an
|
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| * KIND, either express or implied. See the License for the
|
| * specific language governing permissions and limitations
|
| * under the License.
|
| */
|
|
|
| /** @module odata/json */
|
|
|
|
|
|
|
| var utils = require('./../utils.js');
|
| var oDataUtils = require('./odatautils.js');
|
| var oDataHandler = require('./handler.js');
|
|
|
| var odataNs = "odata";
|
| var odataAnnotationPrefix = odataNs + ".";
|
| var contextUrlAnnotation = "@" + odataAnnotationPrefix + "context";
|
|
|
| var assigned = utils.assigned;
|
| var defined = utils.defined;
|
| var isArray = utils.isArray;
|
| //var isDate = utils.isDate;
|
| var isObject = utils.isObject;
|
| //var normalizeURI = utils.normalizeURI;
|
| var parseInt10 = utils.parseInt10;
|
| var getFormatKind = utils.getFormatKind;
|
| var convertByteArrayToHexString = utils.convertByteArrayToHexString;
|
|
|
|
|
| var formatDateTimeOffset = oDataUtils.formatDateTimeOffset;
|
| var formatDuration = oDataUtils.formatDuration;
|
| var formatNumberWidth = oDataUtils.formatNumberWidth;
|
| var getCanonicalTimezone = oDataUtils.getCanonicalTimezone;
|
| var handler = oDataUtils.handler;
|
| var isComplex = oDataUtils.isComplex;
|
| var isPrimitive = oDataUtils.isPrimitive;
|
| var isCollectionType = oDataUtils.isCollectionType;
|
| var lookupComplexType = oDataUtils.lookupComplexType;
|
| var lookupEntityType = oDataUtils.lookupEntityType;
|
| var lookupSingleton = oDataUtils.lookupSingleton;
|
| var lookupEntitySet = oDataUtils.lookupEntitySet;
|
| var lookupDefaultEntityContainer = oDataUtils.lookupDefaultEntityContainer;
|
| var lookupProperty = oDataUtils.lookupProperty;
|
| var MAX_DATA_SERVICE_VERSION = oDataUtils.MAX_DATA_SERVICE_VERSION;
|
| var maxVersion = oDataUtils.maxVersion;
|
|
|
| var isPrimitiveEdmType = oDataUtils.isPrimitiveEdmType;
|
| var isGeographyEdmType = oDataUtils.isGeographyEdmType;
|
| var isGeometryEdmType = oDataUtils.isGeometryEdmType;
|
|
|
| var PAYLOADTYPE_FEED = "f";
|
| var PAYLOADTYPE_ENTRY = "e";
|
| var PAYLOADTYPE_PROPERTY = "p";
|
| var PAYLOADTYPE_COLLECTION = "c";
|
| var PAYLOADTYPE_ENUMERATION_PROPERTY = "enum";
|
| var PAYLOADTYPE_SVCDOC = "s";
|
| var PAYLOADTYPE_ENTITY_REF_LINK = "erl";
|
| var PAYLOADTYPE_ENTITY_REF_LINKS = "erls";
|
|
|
| var PAYLOADTYPE_VALUE = "v";
|
|
|
| var PAYLOADTYPE_DELTA = "d";
|
| var DELTATYPE_FEED = "f";
|
| var DELTATYPE_DELETED_ENTRY = "de";
|
| var DELTATYPE_LINK = "l";
|
| var DELTATYPE_DELETED_LINK = "dl";
|
|
|
| var jsonMediaType = "application/json";
|
| var jsonContentType = oDataHandler.contentType(jsonMediaType);
|
|
|
| var jsonSerializableMetadata = ["@odata.id", "@odata.type"];
|
|
|
|
|
|
|
|
|
|
|
| /** Extend JSON OData payload with metadata
|
| * @param handler - This handler.
|
| * @param text - Payload text (this parser also handles pre-parsed objects).
|
| * @param {Object} context - Object with parsing context.
|
| * @return An object representation of the OData payload.
|
| */
|
| function jsonParser(handler, text, context) {
|
| var recognizeDates = defined(context.recognizeDates, handler.recognizeDates);
|
| var model = context.metadata;
|
| var json = (typeof text === "string") ? JSON.parse(text) : text;
|
| var metadataContentType;
|
| if (assigned(context.contentType) && assigned(context.contentType.properties)) {
|
| metadataContentType = context.contentType.properties["odata.metadata"]; //TODO convert to lower before comparism
|
| }
|
|
|
| var payloadFormat = getFormatKind(metadataContentType, 1); // none: 0, minimal: 1, full: 2
|
|
|
| // No errors should be throw out if we could not parse the json payload, instead we should just return the original json object.
|
| if (payloadFormat === 0) {
|
| return json;
|
| }
|
| else if (payloadFormat === 1) {
|
| return addMinimalMetadataToJsonPayload(json, model, recognizeDates);
|
| }
|
| else if (payloadFormat === 2) {
|
| // to do: using the EDM Model to get the type of each property instead of just guessing.
|
| return addFullMetadataToJsonPayload(json, model, recognizeDates);
|
| }
|
| else {
|
| return json;
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| // The regular expression corresponds to something like this:
|
| // /Date(123+60)/
|
| //
|
| // This first number is date ticks, the + may be a - and is optional,
|
| // with the second number indicating a timezone offset in minutes.
|
| //
|
| // On the wire, the leading and trailing forward slashes are
|
| // escaped without being required to so the chance of collisions is reduced;
|
| // however, by the time we see the objects, the characters already
|
| // look like regular forward slashes.
|
| var jsonDateRE = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/;
|
|
|
|
|
| // Some JSON implementations cannot produce the character sequence \/
|
| // which is needed to format DateTime and DateTimeOffset into the
|
| // JSON string representation defined by the OData protocol.
|
| // See the history of this file for a candidate implementation of
|
| // a 'formatJsonDateString' function.
|
|
|
|
|
| var jsonReplacer = function (_, value) {
|
| /// <summary>JSON replacer function for converting a value to its JSON representation.</summary>
|
| /// <param value type="Object">Value to convert.</param>
|
| /// <returns type="String">JSON representation of the input value.</returns>
|
| /// <remarks>
|
| /// This method is used during JSON serialization and invoked only by the JSON.stringify function.
|
| /// It should never be called directly.
|
| /// </remarks>
|
|
|
| if (value && value.__edmType === "Edm.Time") {
|
| return formatDuration(value);
|
| } else {
|
| return value;
|
| }
|
| };
|
|
|
| /** Serializes a ODataJs payload structure to the wire format which can be send to the server
|
| * @param handler - This handler.
|
| * @param data - Data to serialize.
|
| * @param {Object} context - Object with serialization context.
|
| * @returns {String} The string representation of data.
|
| */
|
| function jsonSerializer(handler, data, context) {
|
|
|
| var dataServiceVersion = context.dataServiceVersion || "4.0";
|
| var cType = context.contentType = context.contentType || jsonContentType;
|
|
|
| if (cType && cType.mediaType === jsonContentType.mediaType) {
|
| context.dataServiceVersion = maxVersion(dataServiceVersion, "4.0");
|
| var newdata = formatJsonRequestPayload(data);
|
| if (newdata) {
|
| return JSON.stringify(newdata,jsonReplacer);
|
| }
|
| }
|
| return undefined;
|
| }
|
|
|
|
|
|
|
|
|
| /** Convert OData objects for serialisation in to a new data structure
|
| * @param data - Data to serialize.
|
| * @returns {String} The string representation of data.
|
| */
|
| function formatJsonRequestPayload(data) {
|
| if (!data) {
|
| return data;
|
| }
|
|
|
| if (isPrimitive(data)) {
|
| return data;
|
| }
|
|
|
| if (isArray(data)) {
|
| var newArrayData = [];
|
| var i, len;
|
| for (i = 0, len = data.length; i < len; i++) {
|
| newArrayData[i] = formatJsonRequestPayload(data[i]);
|
| }
|
|
|
| return newArrayData;
|
| }
|
|
|
| var newdata = {};
|
| for (var property in data) {
|
| if (isJsonSerializableProperty(property)) {
|
| newdata[property] = formatJsonRequestPayload(data[property]);
|
| }
|
| }
|
|
|
| return newdata;
|
| }
|
|
|
| /** Determine form the attribute name if the attribute is a serializable property
|
| * @param attribute
|
| * @returns {boolean}
|
| */
|
| function isJsonSerializableProperty(attribute) {
|
| if (!attribute) {
|
| return false;
|
| }
|
|
|
| if (attribute.indexOf("@odata.") == -1) {
|
| return true;
|
| }
|
|
|
| var i, len;
|
| for (i = 0, len = jsonSerializableMetadata.length; i < len; i++) {
|
| var name = jsonSerializableMetadata[i];
|
| if (attribute.indexOf(name) != -1) {
|
| return true;
|
| }
|
| }
|
|
|
| return false;
|
| }
|
|
|
| /** Creates an object containing information for the json payload.
|
| * @param {String} kind - JSON payload kind
|
| * @param {String} type - Type name of the JSON payload.
|
| * @returns {Object} Object with kind and type fields.
|
| */
|
| function jsonMakePayloadInfo(kind, type) {
|
| return { kind: kind, type: type || null };
|
| }
|
|
|
|
|
|
|
| /** Add metadata to an JSON payload complex object containing full metadata
|
| * @param {Object} data - Data structure to be extended
|
| * @param {Object} model - Metadata model
|
| * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.
|
| */
|
| function addFullMetadataToJsonPayload(data, model, recognizeDates) {
|
| var type;
|
| if (utils.isObject(data)) {
|
| for (var key in data) {
|
| if (data.hasOwnProperty(key)) {
|
| if (key.indexOf('@') === -1) {
|
| if (utils.isArray(data[key])) {
|
| for (var i = 0; i < data[key].length; ++i) {
|
| addFullMetadataToJsonPayload(data[key][i], model, recognizeDates);
|
| }
|
| } else if (utils.isObject(data[key])) {
|
| if (data[key] !== null) {
|
| //don't step into geo.. objects
|
| type = data[key+'@odata.type'];
|
| if (!type) {
|
| //type unknown
|
| addFullMetadataToJsonPayload(data[key], model, recognizeDates);
|
| } else {
|
| type = type.substring(1);
|
| if (isGeographyEdmType(type) || isGeometryEdmType(type)) {
|
| // don't add type info for geo* types
|
| } else {
|
| addFullMetadataToJsonPayload(data[key], model, recognizeDates);
|
| }
|
| }
|
| }
|
| } else {
|
| type = data[key + '@odata.type'];
|
|
|
| // On .Net OData library, some basic EDM type is omitted, e.g. Edm.String, Edm.Int, and etc.
|
| // For the full metadata payload, we need to full fill the @data.type for each property if it is missing.
|
| // We do this is to help the OlingoJS consumers to easily get the type of each property.
|
| if (!assigned(type)) {
|
| // Guessing the "type" from the type of the value is not the right way here.
|
| // To do: we need to get the type from metadata instead of guessing.
|
| var typeFromObject = typeof data[key];
|
| if (typeFromObject === 'string') {
|
| addType(data, key, 'String');
|
| } else if (typeFromObject === 'boolean') {
|
| addType(data, key, 'Boolean');
|
| } else if (typeFromObject === 'number') {
|
| if (data[key] % 1 === 0) { // has fraction
|
| addType(data, key, 'Int32'); // the biggst integer
|
| } else {
|
| addType(data, key, 'Decimal'); // the biggst float single,doulbe,decimal
|
| }
|
| }
|
| }
|
| else {
|
| if (recognizeDates) {
|
| convertDatesNoEdm(data, key, type.substring(1));
|
| }
|
| }
|
| }
|
| }
|
| }
|
| }
|
| }
|
|
|
| return data;
|
| }
|
|
|
| /** Loop through the properties of an JSON payload object, look up the type info of the property and call
|
| * the appropriate add*MetadataToJsonPayloadObject function
|
| * @param {Object} data - Data structure to be extended
|
| * @param {String} objectInfoType - Information about the data (name,type,typename,...)
|
| * @param {String} baseURI - Base Url
|
| * @param {Object} model - Metadata model
|
| * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.
|
| */
|
| function checkProperties(data, objectInfoType, baseURI, model, recognizeDates) {
|
| for (var name in data) {
|
| if (name.indexOf("@") === -1) {
|
| var curType = objectInfoType;
|
| var propertyValue = data[name];
|
| var property = lookupProperty(curType.property,name); //TODO SK add check for parent type
|
|
|
| while (( property === null) && (curType.baseType !== undefined)) {
|
| curType = lookupEntityType(curType.baseType, model);
|
| property = lookupProperty(curType.property,name);
|
| }
|
|
|
| if ( isArray(propertyValue)) {
|
| //data[name+'@odata.type'] = '#' + property.type;
|
| if (isCollectionType(property.type)) {
|
| addTypeColNoEdm(data,name,property.type.substring(11,property.type.length-1));
|
| } else {
|
| addTypeNoEdm(data,name,property.type);
|
| }
|
|
|
|
|
| for ( var i = 0; i < propertyValue.length; i++) {
|
| addMetadataToJsonMinimalPayloadComplex(propertyValue[i], property, baseURI, model, recognizeDates);
|
| }
|
| } else if (isObject(propertyValue) && (propertyValue !== null)) {
|
| addMetadataToJsonMinimalPayloadComplex(propertyValue, property, baseURI, model, recognizeDates);
|
| } else {
|
| //data[name+'@odata.type'] = '#' + property.type;
|
| addTypeNoEdm(data,name,property.type);
|
| if (recognizeDates) {
|
| convertDates(data, name, property.type);
|
| }
|
| }
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
| /** Add metadata to an JSON payload object containing minimal metadata
|
| * @param {Object} data - Json response payload object
|
| * @param {Object} model - Object describing an OData conceptual schema
|
| * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.
|
| * @returns {Object} Object in the library's representation.
|
| */
|
| function addMinimalMetadataToJsonPayload(data, model, recognizeDates) {
|
|
|
| if (!assigned(model) || isArray(model)) {
|
| return data;
|
| }
|
|
|
| var baseURI = data[contextUrlAnnotation];
|
| var payloadInfo = createPayloadInfo(data, model);
|
|
|
| switch (payloadInfo.detectedPayloadKind) {
|
|
|
| case PAYLOADTYPE_VALUE:
|
| if (payloadInfo.type !== null) {
|
| return addMetadataToJsonMinimalPayloadEntity(data, payloadInfo, baseURI, model, recognizeDates);
|
| } else {
|
| return addTypeNoEdm(data,'value', payloadInfo.typeName);
|
| }
|
|
|
| case PAYLOADTYPE_FEED:
|
| return addMetadataToJsonMinimalPayloadFeed(data, model, payloadInfo, baseURI, recognizeDates);
|
|
|
| case PAYLOADTYPE_ENTRY:
|
| return addMetadataToJsonMinimalPayloadEntity(data, payloadInfo, baseURI, model, recognizeDates);
|
|
|
| case PAYLOADTYPE_COLLECTION:
|
| return addMetadataToJsonMinimalPayloadCollection(data, model, payloadInfo, baseURI, recognizeDates);
|
|
|
| case PAYLOADTYPE_PROPERTY:
|
| if (payloadInfo.type !== null) {
|
| return addMetadataToJsonMinimalPayloadEntity(data, payloadInfo, baseURI, model, recognizeDates);
|
| } else {
|
| return addTypeNoEdm(data,'value', payloadInfo.typeName);
|
| }
|
|
|
| case PAYLOADTYPE_SVCDOC:
|
| return data;
|
|
|
| case PAYLOADTYPE_LINKS:
|
| return data;
|
| }
|
|
|
| return data;
|
| }
|
|
|
| /** Add metadata to an JSON payload feed object containing minimal metadata
|
| * @param {Object} data - Data structure to be extended
|
| * @param {Object} model - Metadata model
|
| * @param {String} feedInfo - Information about the data (name,type,typename,...)
|
| * @param {String} baseURI - Base Url
|
| * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.
|
| */
|
| function addMetadataToJsonMinimalPayloadFeed(data, model, feedInfo, baseURI, recognizeDates) {
|
| var entries = [];
|
| var items = data.value;
|
| var i,len;
|
| var entry;
|
| for (i = 0, len = items.length; i < len; i++) {
|
| var item = items[i];
|
| if ( defined(item['@odata.type'])) { // in case of mixed feeds
|
| var typeName = item['@odata.type'].substring(1);
|
| var type = lookupEntityType( typeName, model);
|
| var entryInfo = {
|
| contentTypeOdata : feedInfo.contentTypeOdata,
|
| detectedPayloadKind : feedInfo.detectedPayloadKind,
|
| name : feedInfo.name,
|
| type : type,
|
| typeName : typeName
|
| };
|
|
|
| entry = addMetadataToJsonMinimalPayloadEntity(item, entryInfo, baseURI, model, recognizeDates);
|
| } else {
|
| entry = addMetadataToJsonMinimalPayloadEntity(item, feedInfo, baseURI, model, recognizeDates);
|
| }
|
|
|
| entries.push(entry);
|
| }
|
| data.value = entries;
|
| return data;
|
| }
|
|
|
|
|
| /** Add metadata to an JSON payload entity object containing minimal metadata
|
| * @param {Object} data - Data structure to be extended
|
| * @param {String} objectInfo - Information about the data (name,type,typename,...)
|
| * @param {String} baseURI - Base Url
|
| * @param {Object} model - Metadata model
|
| * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.
|
| */
|
| function addMetadataToJsonMinimalPayloadEntity(data, objectInfo, baseURI, model, recognizeDates) {
|
| addType(data,'',objectInfo.typeName);
|
|
|
| var keyType = objectInfo.type;
|
| while ((defined(keyType)) && ( keyType.key === undefined) && (keyType.baseType !== undefined)) {
|
| keyType = lookupEntityType(keyType.baseType, model);
|
| }
|
|
|
| if (keyType.key !== undefined) {
|
| var lastIdSegment = objectInfo.name + jsonGetEntryKey(data, keyType);
|
| data['@odata.id'] = baseURI.substring(0, baseURI.lastIndexOf("$metadata")) + lastIdSegment;
|
| data['@odata.editLink'] = lastIdSegment;
|
| }
|
|
|
| //var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata"));
|
|
|
| checkProperties(data, objectInfo.type, baseURI, model, recognizeDates);
|
|
|
| return data;
|
| }
|
|
|
| /** Add metadata to an JSON payload complex object containing minimal metadata
|
| * @param {Object} data - Data structure to be extended
|
| * @param {String} property - Information about the data (name,type,typename,...)
|
| * @param {String} baseURI - Base Url
|
| * @param {Object} model - Metadata model
|
| * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.
|
| */
|
| function addMetadataToJsonMinimalPayloadComplex(data, property, baseURI, model, recognizeDates) {
|
| var type = property.type;
|
| if (isCollectionType(property.type)) {
|
| type =property.type.substring(11,property.type.length-1);
|
| }
|
|
|
| addType(data,'',property.type);
|
|
|
| var propertyType = lookupComplexType(type, model);
|
| if (propertyType === null) {
|
| return; //TODO check what to do if the type is not known e.g. type #GeometryCollection
|
| }
|
|
|
| checkProperties(data, propertyType, baseURI, model, recognizeDates);
|
| }
|
|
|
| /** Add metadata to an JSON payload collection object containing minimal metadata
|
| * @param {Object} data - Data structure to be extended
|
| * @param {Object} model - Metadata model
|
| * @param {String} collectionInfo - Information about the data (name,type,typename,...)
|
| * @param {String} baseURI - Base Url
|
| * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects.
|
| */
|
| function addMetadataToJsonMinimalPayloadCollection(data, model, collectionInfo, baseURI, recognizeDates) {
|
|
|
| addTypeColNoEdm(data,'', collectionInfo.typeName);
|
|
|
| if (collectionInfo.type !== null) {
|
| var entries = [];
|
|
|
| var items = data.value;
|
| var i,len;
|
| var entry;
|
| for (i = 0, len = items.length; i < len; i++) {
|
| var item = items[i];
|
| if ( defined(item['@odata.type'])) { // in case of mixed collections
|
| var typeName = item['@odata.type'].substring(1);
|
| var type = lookupEntityType( typeName, model);
|
| var entryInfo = {
|
| contentTypeOdata : collectionInfo.contentTypeOdata,
|
| detectedPayloadKind : collectionInfo.detectedPayloadKind,
|
| name : collectionInfo.name,
|
| type : type,
|
| typeName : typeName
|
| };
|
|
|
| entry = addMetadataToJsonMinimalPayloadEntity(item, entryInfo, baseURI, model, recognizeDates);
|
| } else {
|
| entry = addMetadataToJsonMinimalPayloadEntity(item, collectionInfo, baseURI, model, recognizeDates);
|
| }
|
|
|
| entries.push(entry);
|
| }
|
| data.value = entries;
|
| }
|
| return data;
|
| }
|
|
|
| /** Add an OData type tag to an JSON payload object
|
| * @param {Object} data - Data structure to be extended
|
| * @param {String} name - Name of the property whose type is set
|
| * @param {String} value - Type name
|
| */
|
| function addType(data, name, value ) {
|
| var fullName = name + '@odata.type';
|
|
|
| if ( data[fullName] === undefined) {
|
| data[fullName] = '#' + value;
|
| }
|
| }
|
|
|
| /** Add an OData type tag to an JSON payload object collection (without "Edm." namespace)
|
| * @param {Object} data - Data structure to be extended
|
| * @param {String} name - Name of the property whose type is set
|
| * @param {String} typeName - Type name
|
| */
|
| function addTypeColNoEdm(data, name, typeName ) {
|
| var fullName = name + '@odata.type';
|
|
|
| if ( data[fullName] === undefined) {
|
| if ( typeName.substring(0,4)==='Edm.') {
|
| data[fullName] = '#Collection('+typeName.substring(4)+ ')';
|
| } else {
|
| data[fullName] = '#Collection('+typeName+ ')';
|
| }
|
| }
|
| }
|
|
|
|
|
| /** Add an OData type tag to an JSON payload object (without "Edm." namespace)
|
| * @param {Object} data - Data structure to be extended
|
| * @param {String} name - Name of the property whose type is set
|
| * @param {String} value - Type name
|
| */
|
| function addTypeNoEdm(data, name, value ) {
|
| var fullName = name + '@odata.type';
|
|
|
| if ( data[fullName] === undefined) {
|
| if ( value.substring(0,4)==='Edm.') {
|
| data[fullName] = '#' + value.substring(4);
|
| } else {
|
| data[fullName] = '#' + value;
|
| }
|
| }
|
| return data;
|
| }
|
| /** Convert the date/time format of an property from the JSON payload object (without "Edm." namespace)
|
| * @param {Object} data - Data structure to be extended
|
| * @param propertyName - Name of the property to be changed
|
| * @param type - Type
|
| */
|
| function convertDates(data, propertyName,type) {
|
| if (type === 'Edm.Date') {
|
| data[propertyName] = oDataUtils.parseDate(data[propertyName], true);
|
| } else if (type === 'Edm.DateTimeOffset') {
|
| data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true);
|
| } else if (type === 'Edm.Duration') {
|
| data[propertyName] = oDataUtils.parseDuration(data[propertyName], true);
|
| } else if (type === 'Edm.Time') {
|
| data[propertyName] = oDataUtils.parseTime(data[propertyName], true);
|
| }
|
| }
|
|
|
| /** Convert the date/time format of an property from the JSON payload object
|
| * @param {Object} data - Data structure to be extended
|
| * @param propertyName - Name of the property to be changed
|
| * @param type - Type
|
| */
|
| function convertDatesNoEdm(data, propertyName,type) {
|
| if (type === 'Date') {
|
| data[propertyName] = oDataUtils.parseDate(data[propertyName], true);
|
| } else if (type === 'DateTimeOffset') {
|
| data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true);
|
| } else if (type === 'Duration') {
|
| data[propertyName] = oDataUtils.parseDuration(data[propertyName], true);
|
| } else if (type === 'Time') {
|
| data[propertyName] = oDataUtils.parseTime(data[propertyName], true);
|
| }
|
| }
|
|
|
| /** Formats a value according to Uri literal format
|
| * @param value - Value to be formatted.
|
| * @param type - Edm type of the value
|
| * @returns {string} Value after formatting
|
| */
|
| function formatLiteral(value, type) {
|
|
|
| value = "" + formatRawLiteral(value, type);
|
| value = encodeURIComponent(value.replace("'", "''"));
|
| switch ((type)) {
|
| case "Edm.Binary":
|
| return "X'" + value + "'";
|
| case "Edm.DateTime":
|
| return "datetime" + "'" + value + "'";
|
| case "Edm.DateTimeOffset":
|
| return "datetimeoffset" + "'" + value + "'";
|
| case "Edm.Decimal":
|
| return value + "M";
|
| case "Edm.Guid":
|
| return "guid" + "'" + value + "'";
|
| case "Edm.Int64":
|
| return value + "L";
|
| case "Edm.Float":
|
| return value + "f";
|
| case "Edm.Double":
|
| return value + "D";
|
| case "Edm.Geography":
|
| return "geography" + "'" + value + "'";
|
| case "Edm.Geometry":
|
| return "geometry" + "'" + value + "'";
|
| case "Edm.Time":
|
| return "time" + "'" + value + "'";
|
| case "Edm.String":
|
| return "'" + value + "'";
|
| default:
|
| return value;
|
| }
|
| }
|
|
|
| /** convert raw byteArray to hexString if the property is an binary property
|
| * @param value - Value to be formatted.
|
| * @param type - Edm type of the value
|
| * @returns {string} Value after formatting
|
| */
|
| function formatRawLiteral(value, type) {
|
| switch (type) {
|
| case "Edm.Binary":
|
| return convertByteArrayToHexString(value);
|
| default:
|
| return value;
|
| }
|
| }
|
|
|
| /** Formats the given minutes into (+/-)hh:mm format.
|
| * @param {Number} minutes - Number of minutes to format.
|
| * @returns {String} The minutes in (+/-)hh:mm format.
|
| */
|
| function minutesToOffset(minutes) {
|
|
|
| var sign;
|
| if (minutes < 0) {
|
| sign = "-";
|
| minutes = -minutes;
|
| } else {
|
| sign = "+";
|
| }
|
|
|
| var hours = Math.floor(minutes / 60);
|
| minutes = minutes - (60 * hours);
|
|
|
| return sign + formatNumberWidth(hours, 2) + ":" + formatNumberWidth(minutes, 2);
|
| }
|
|
|
| /** Parses the JSON Date representation into a Date object.
|
| * @param {String} value - String value.
|
| * @returns {Date} A Date object if the value matches one; falsy otherwise.
|
| */
|
| function parseJsonDateString(value) {
|
|
|
| var arr = value && jsonDateRE.exec(value);
|
| if (arr) {
|
| // 0 - complete results; 1 - ticks; 2 - sign; 3 - minutes
|
| var result = new Date(parseInt10(arr[1]));
|
| if (arr[2]) {
|
| var mins = parseInt10(arr[3]);
|
| if (arr[2] === "-") {
|
| mins = -mins;
|
| }
|
|
|
| // The offset is reversed to get back the UTC date, which is
|
| // what the API will eventually have.
|
| var current = result.getUTCMinutes();
|
| result.setUTCMinutes(current - mins);
|
| result.__edmType = "Edm.DateTimeOffset";
|
| result.__offset = minutesToOffset(mins);
|
| }
|
| if (!isNaN(result.valueOf())) {
|
| return result;
|
| }
|
| }
|
|
|
| // Allow undefined to be returned.
|
| }
|
|
|
| /** Creates an object containing information for the context
|
| * @param {String} fragments - Uri fragment
|
| * @param {Object} model - Object describing an OData conceptual schema
|
| * @returns {Object} type(optional) object containing type information for entity- and complex-types ( null if a typeName is a primitive)
|
| */
|
| function parseContextUriFragment( fragments, model ) {
|
| var ret = {};
|
|
|
| if (fragments.indexOf('/') === -1 ) {
|
| if (fragments.length === 0) {
|
| // Capter 10.1
|
| ret.detectedPayloadKind = PAYLOADTYPE_SVCDOC;
|
| return ret;
|
| } else if (fragments === 'Edm.Null') {
|
| // Capter 10.15
|
| ret.detectedPayloadKind = PAYLOADTYPE_VALUE;
|
| ret.isNullProperty = true;
|
| return ret;
|
| } else if (fragments === 'Collection($ref)') {
|
| // Capter 10.11
|
| ret.detectedPayloadKind = PAYLOADTYPE_ENTITY_REF_LINKS;
|
| return ret;
|
| } else if (fragments === '$ref') {
|
| // Capter 10.12
|
| ret.detectedPayloadKind = PAYLOADTYPE_ENTITY_REF_LINK;
|
| return ret;
|
| } else {
|
| //TODO check for navigation resource
|
| }
|
| }
|
|
|
| ret.type = undefined;
|
| ret.typeName = undefined;
|
|
|
| var fragmentParts = fragments.split("/");
|
| var type;
|
|
|
| for(var i = 0; i < fragmentParts.length; ++i) {
|
| var fragment = fragmentParts[i];
|
| if (ret.typeName === undefined) {
|
| //preparation
|
| if ( fragment.indexOf('(') !== -1 ) {
|
| //remove the query function, cut fragment to matching '('
|
| var index = fragment.length - 2 ;
|
| for ( var rCount = 1; rCount > 0 && index > 0; --index) {
|
| if ( fragment.charAt(index)=='(') {
|
| rCount --;
|
| } else if ( fragment.charAt(index)==')') {
|
| rCount ++;
|
| }
|
| }
|
|
|
| if (index === 0) {
|
| //TODO throw error
|
| }
|
|
|
| //remove the projected entity from the fragment; TODO decide if we want to store the projected entity
|
| var inPharenthesis = fragment.substring(index+2,fragment.length - 1);
|
| fragment = fragment.substring(0,index+1);
|
|
|
| if (utils.startsWith(fragment, 'Collection')) {
|
| ret.detectedPayloadKind = PAYLOADTYPE_COLLECTION;
|
| // Capter 10.14
|
| ret.typeName = inPharenthesis;
|
|
|
| type = lookupEntityType(ret.typeName, model);
|
| if ( type !== null) {
|
| ret.type = type;
|
| continue;
|
| }
|
| type = lookupComplexType(ret.typeName, model);
|
| if ( type !== null) {
|
| ret.type = type;
|
| continue;
|
| }
|
|
|
| ret.type = null;//in case of #Collection(Edm.String) only lastTypeName is filled
|
| continue;
|
| } else {
|
| // projection: Capter 10.7, 10.8 and 10.9
|
| ret.projection = inPharenthesis;
|
| }
|
| }
|
|
|
|
|
| if (jsonIsPrimitiveType(fragment)) {
|
| ret.typeName = fragment;
|
| ret.type = null;
|
| ret.detectedPayloadKind = PAYLOADTYPE_VALUE;
|
| continue;
|
| }
|
|
|
| var container = lookupDefaultEntityContainer(model);
|
|
|
| //check for entity
|
| var entitySet = lookupEntitySet(container.entitySet, fragment);
|
| if ( entitySet !== null) {
|
| ret.typeName = entitySet.entityType;
|
| ret.type = lookupEntityType( ret.typeName, model);
|
| ret.name = fragment;
|
| ret.detectedPayloadKind = PAYLOADTYPE_FEED;
|
| // Capter 10.2
|
| continue;
|
| }
|
|
|
| //check for singleton
|
| var singleton = lookupSingleton(container.singleton, fragment);
|
| if ( singleton !== null) {
|
| ret.typeName = singleton.entityType;
|
| ret.type = lookupEntityType( ret.typeName, model);
|
| ret.name = fragment;
|
| ret.detectedPayloadKind = PAYLOADTYPE_ENTRY;
|
| // Capter 10.4
|
| continue;
|
| }
|
|
|
|
|
|
|
| //TODO throw ERROR
|
| } else {
|
| //check for $entity
|
| if (utils.endsWith(fragment, '$entity') && (ret.detectedPayloadKind === PAYLOADTYPE_FEED)) {
|
| //TODO ret.name = fragment;
|
| ret.detectedPayloadKind = PAYLOADTYPE_ENTRY;
|
| // Capter 10.3 and 10.6
|
| continue;
|
| }
|
|
|
| //check for derived types
|
| if (fragment.indexOf('.') !== -1) {
|
| // Capter 10.6
|
| ret.typeName = fragment;
|
| type = lookupEntityType(ret.typeName, model);
|
| if ( type !== null) {
|
| ret.type = type;
|
| continue;
|
| }
|
| type = lookupComplexType(ret.typeName, model);
|
| if ( type !== null) {
|
| ret.type = type;
|
| continue;
|
| }
|
|
|
| //TODO throw ERROR invalid type
|
| }
|
|
|
| //check for property value
|
| if ( ret.detectedPayloadKind === PAYLOADTYPE_FEED || ret.detectedPayloadKind === PAYLOADTYPE_ENTRY) {
|
| var property = lookupProperty(ret.type.property, fragment);
|
| if (property !== null) {
|
| //PAYLOADTYPE_COLLECTION
|
| ret.typeName = property.type;
|
|
|
|
|
| if (utils.startsWith(property.type, 'Collection')) {
|
| ret.detectedPayloadKind = PAYLOADTYPE_COLLECTION;
|
| var tmp12 = property.type.substring(10+1,property.type.length - 1);
|
| ret.typeName = tmp12;
|
| ret.type = lookupComplexType(tmp12, model);
|
| ret.detectedPayloadKind = PAYLOADTYPE_COLLECTION;
|
| } else {
|
| ret.type = lookupComplexType(property.type, model);
|
| ret.detectedPayloadKind = PAYLOADTYPE_PROPERTY;
|
| }
|
|
|
| ret.name = fragment;
|
| // Capter 10.15
|
| }
|
| continue;
|
| }
|
|
|
| if (fragment === '$delta') {
|
| ret.deltaKind = DELTATYPE_FEED;
|
| continue;
|
| } else if (utils.endsWith(fragment, '/$deletedEntity')) {
|
| ret.deltaKind = DELTATYPE_DELETED_ENTRY;
|
| continue;
|
| } else if (utils.endsWith(fragment, '/$link')) {
|
| ret.deltaKind = DELTATYPE_LINK;
|
| continue;
|
| } else if (utils.endsWith(fragment, '/$deletedLink')) {
|
| ret.deltaKind = DELTATYPE_DELETED_LINK;
|
| continue;
|
| }
|
| //TODO throw ERROr
|
| }
|
| }
|
|
|
| return ret;
|
| }
|
|
|
|
|
| /** Infers the information describing the JSON payload from its metadata annotation, structure, and data model.
|
| * @param {Object} data - Json response payload object.
|
| * @param {Object} model - Object describing an OData conceptual schema.
|
| * If the arguments passed to the function don't convey enough information about the payload to determine without doubt that the payload is a feed then it
|
| * will try to use the payload object structure instead. If the payload looks like a feed (has value property that is an array or non-primitive values) then
|
| * the function will report its kind as PAYLOADTYPE_FEED unless the inferFeedAsComplexType flag is set to true. This flag comes from the user request
|
| * and allows the user to control how the library behaves with an ambigous JSON payload.
|
| * @return Object with kind and type fields. Null if there is no metadata annotation or the payload info cannot be obtained..
|
| */
|
| function createPayloadInfo(data, model) {
|
| var metadataUri = data[contextUrlAnnotation];
|
| if (!metadataUri || typeof metadataUri !== "string") {
|
| return null;
|
| }
|
|
|
| var fragmentStart = metadataUri.lastIndexOf("#");
|
| if (fragmentStart === -1) {
|
| return jsonMakePayloadInfo(PAYLOADTYPE_SVCDOC);
|
| }
|
|
|
| var fragment = metadataUri.substring(fragmentStart + 1);
|
| return parseContextUriFragment(fragment,model);
|
| }
|
| /** Gets the key of an entry.
|
| * @param {Object} data - JSON entry.
|
| * @param {Object} data - EDM entity model for key loockup.
|
| * @returns {string} Entry instance key.
|
| */
|
| function jsonGetEntryKey(data, entityModel) {
|
|
|
| var entityInstanceKey;
|
| var entityKeys = entityModel.key[0].propertyRef;
|
| var type;
|
| entityInstanceKey = "(";
|
| if (entityKeys.length == 1) {
|
| type = lookupProperty(entityModel.property, entityKeys[0].name).type;
|
| entityInstanceKey += formatLiteral(data[entityKeys[0].name], type);
|
| } else {
|
| var first = true;
|
| for (var i = 0; i < entityKeys.length; i++) {
|
| if (!first) {
|
| entityInstanceKey += ",";
|
| } else {
|
| first = false;
|
| }
|
| type = lookupProperty(entityModel.property, entityKeys[i].name).type;
|
| entityInstanceKey += entityKeys[i].name + "=" + formatLiteral(data[entityKeys[i].name], type);
|
| }
|
| }
|
| entityInstanceKey += ")";
|
| return entityInstanceKey;
|
| }
|
| /** Determines whether a type name is a primitive type in a JSON payload.
|
| * @param {String} typeName - Type name to test.
|
| * @returns {Boolean} True if the type name an EDM primitive type or an OData spatial type; false otherwise.
|
| */
|
| function jsonIsPrimitiveType(typeName) {
|
| return isPrimitiveEdmType(typeName) || isGeographyEdmType(typeName) || isGeometryEdmType(typeName);
|
| }
|
|
|
|
|
| var jsonHandler = oDataHandler.handler(jsonParser, jsonSerializer, jsonMediaType, MAX_DATA_SERVICE_VERSION);
|
| jsonHandler.recognizeDates = false;
|
|
|
| exports.createPayloadInfo = createPayloadInfo;
|
| exports.jsonHandler = jsonHandler;
|
| exports.jsonParser = jsonParser;
|
| exports.jsonSerializer = jsonSerializer;
|
| exports.parseJsonDateString = parseJsonDateString;</code></pre> |
| </article> |
| </section> |
| |
| |
| |
| |
| </div> |
| |
| <nav> |
| <h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="module-cache.html">cache</a></li><li><a href="source.html">cache/source</a></li><li><a href="module-odata.html">odata</a></li><li><a href="batch.html">odata/batch</a></li><li><a href="handler.html">odata/handler</a></li><li><a href="json.html">odata/json</a></li><li><a href="metadata.html">odata/metadata</a></li><li><a href="net.html">odata/net</a></li><li><a href="utils.html">odata/utils</a></li><li><a href="deferred.html">odatajs/deferred</a></li><li><a href="utils_.html">odatajs/utils</a></li><li><a href="xml.html">odatajs/xml</a></li><li><a href="module-store.html">store</a></li><li><a href="dom.html">store/dom</a></li><li><a href="indexeddb.html">store/indexeddb</a></li><li><a href="memory.html">store/memory</a></li></ul><h3>Classes</h3><ul><li><a href="DataCache.html">DataCache</a></li><li><a href="DataCacheOperation.html">DataCacheOperation</a></li><li><a href="DjsDeferred.html">DjsDeferred</a></li><li><a href="dom-DomStore.html">DomStore</a></li><li><a href="indexeddb-IndexedDBStore.html">IndexedDBStore</a></li><li><a href="memory-MemoryStore.html">MemoryStore</a></li><li><a href="ODataCacheSource.html">ODataCacheSource</a></li></ul><h3><a href="global.html">Global</a></h3> |
| </nav> |
| |
| <br clear="both"> |
| |
| <footer> |
| Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Thu Apr 09 2015 08:31:26 GMT+0200 (MESZ) |
| </footer> |
| |
| <script> prettyPrint(); </script> |
| <script src="scripts/linenumber.js"> </script> |
| </body> |
| </html> |