http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/503b4417/odatajs/src/lib/odata/batch.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/batch.js b/odatajs/src/lib/odata/batch.js deleted file mode 100644 index c71fc31..0000000 --- a/odatajs/src/lib/odata/batch.js +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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/batch */ - -var utils = require('./../utils.js'); -var odataUtils = require('./odatautils.js'); -var odataHandler = require('./handler.js'); - -var extend = utils.extend; -var isArray = utils.isArray; -var trimString = utils.trimString; - -var contentType = odataHandler.contentType; -var handler = odataHandler.handler; -var isBatch = odataUtils.isBatch; -var MAX_DATA_SERVICE_VERSION = odataHandler.MAX_DATA_SERVICE_VERSION; -var normalizeHeaders = odataUtils.normalizeHeaders; -//TODO var payloadTypeOf = odata.payloadTypeOf; -var prepareRequest = odataUtils.prepareRequest; - - - - - -// Imports - - - -// CONTENT START -var batchMediaType = "multipart/mixed"; -var responseStatusRegex = /^HTTP\/1\.\d (\d{3}) (.*)$/i; -var responseHeaderRegex = /^([^()<>@,;:\\"\/[\]?={} \t]+)\s?:\s?(.*)/; - -/* Calculates a random 16 bit number and returns it in hexadecimal format. - * @returns {String} A 16-bit number in hex format. - */ -function hex16() { - - return Math.floor((1 + Math.random()) * 0x10000).toString(16).substr(1); -} - -/* Creates a string that can be used as a multipart request boundary. - * @param {String} [prefix] - - * @returns {String} Boundary string of the format: <prefix><hex16>-<hex16>-<hex16> - */ -function createBoundary(prefix) { - - return prefix + hex16() + "-" + hex16() + "-" + hex16(); -} - -/* Gets the handler for data serialization of individual requests / responses in a batch. - * @param context - Context used for data serialization. - * @returns Handler object - */ -function partHandler(context) { - - return context.handler.partHandler; -} - -/* Gets the current boundary used for parsing the body of a multipart response. - * @param context - Context used for parsing a multipart response. - * @returns {String} Boundary string. - */ -function currentBoundary(context) { - var boundaries = context.boundaries; - return boundaries[boundaries.length - 1]; -} - -/** Parses a batch response. - * @param handler - This handler. - * @param {String} text - Batch text. - * @param {Object} context - Object with parsing context. - * @return An object representation of the batch. - */ -function batchParser(handler, text, context) { - - var boundary = context.contentType.properties["boundary"]; - return { __batchResponses: readBatch(text, { boundaries: [boundary], handlerContext: context }) }; -} - -/** Serializes a batch object representation into text. - * @param handler - This handler. - * @param {Object} data - Representation of a batch. - * @param {Object} context - Object with parsing context. - * @return An text representation of the batch object; undefined if not applicable.# - */ -function batchSerializer(handler, data, context) { - - var cType = context.contentType = context.contentType || contentType(batchMediaType); - if (cType.mediaType === batchMediaType) { - return writeBatch(data, context); - } -} - -/* Parses a multipart/mixed response body from from the position defined by the context. - * @param {String} text - Body of the multipart/mixed response. - * @param context - Context used for parsing. - * @return Array of objects representing the individual responses. - */ -function readBatch(text, context) { - var delimiter = "--" + currentBoundary(context); - - // Move beyond the delimiter and read the complete batch - readTo(text, context, delimiter); - - // Ignore the incoming line - readLine(text, context); - - // Read the batch parts - var responses = []; - var partEnd; - - while (partEnd !== "--" && context.position < text.length) { - var partHeaders = readHeaders(text, context); - var partContentType = contentType(partHeaders["Content-Type"]); - - var changeResponses; - if (partContentType && partContentType.mediaType === batchMediaType) { - context.boundaries.push(partContentType.properties.boundary); - try { - changeResponses = readBatch(text, context); - } catch (e) { - e.response = readResponse(text, context, delimiter); - changeResponses = [e]; - } - responses.push({ __changeResponses: changeResponses }); - context.boundaries.pop(); - readTo(text, context, "--" + currentBoundary(context)); - } else { - if (!partContentType || partContentType.mediaType !== "application/http") { - throw { message: "invalid MIME part type " }; - } - // Skip empty line - readLine(text, context); - // Read the response - var response = readResponse(text, context, delimiter); - try { - if (response.statusCode >= 200 && response.statusCode <= 299) { - partHandler(context.handlerContext).read(response, context.handlerContext); - } else { - // Keep track of failed responses and continue processing the batch. - response = { message: "HTTP request failed", response: response }; - } - } catch (e) { - response = e; - } - - responses.push(response); - } - - partEnd = text.substr(context.position, 2); - - // Ignore the incoming line. - readLine(text, context); - } - return responses; -} - -/* Parses the http headers in the text from the position defined by the context. -* @param {String} text - Text containing an http response's headers</param> -* @param context - Context used for parsing. -* @returns Object containing the headers as key value pairs. -* This function doesn't support split headers and it will stop reading when it hits two consecutive line breaks. -*/ -function readHeaders(text, context) { - var headers = {}; - var parts; - var line; - var pos; - - do { - pos = context.position; - line = readLine(text, context); - parts = responseHeaderRegex.exec(line); - if (parts !== null) { - headers[parts[1]] = parts[2]; - } else { - // Whatever was found is not a header, so reset the context position. - context.position = pos; - } - } while (line && parts); - - normalizeHeaders(headers); - - return headers; -} - -/* Parses an HTTP response. - * @param {String} text -Text representing the http response. - * @param context optional - Context used for parsing. - * @param {String} delimiter -String used as delimiter of the multipart response parts. - * @return Object representing the http response. - */ -function readResponse(text, context, delimiter) { - // Read the status line. - var pos = context.position; - var match = responseStatusRegex.exec(readLine(text, context)); - - var statusCode; - var statusText; - var headers; - - if (match) { - statusCode = match[1]; - statusText = match[2]; - headers = readHeaders(text, context); - readLine(text, context); - } else { - context.position = pos; - } - - return { - statusCode: statusCode, - statusText: statusText, - headers: headers, - body: readTo(text, context, "\r\n" + delimiter) - }; -} - -/** Returns a substring from the position defined by the context up to the next line break (CRLF). - * @param {String} text - Input string. - * @param context - Context used for reading the input string. - * @returns {String} Substring to the first ocurrence of a line break or null if none can be found. - */ -function readLine(text, context) { - - return readTo(text, context, "\r\n"); -} - -/** Returns a substring from the position given by the context up to value defined by the str parameter and increments the position in the context. - * @param {String} text - Input string.</param> - * @param context - Context used for reading the input string.</param> - * @param {String} [str] - Substring to read up to. - * @returns {String} Substring to the first ocurrence of str or the end of the input string if str is not specified. Null if the marker is not found. - */ -function readTo(text, context, str) { - var start = context.position || 0; - var end = text.length; - if (str) { - end = text.indexOf(str, start); - if (end === -1) { - return null; - } - context.position = end + str.length; - } else { - context.position = end; - } - - return text.substring(start, end); -} - -/** Serializes a batch request object to a string. - * @param data - Batch request object in payload representation format - * @param context - Context used for the serialization - * @returns {String} String representing the batch request - */ -function writeBatch(data, context) { - if (!isBatch(data)) { - throw { message: "Data is not a batch object." }; - } - - var batchBoundary = createBoundary("batch_"); - var batchParts = data.__batchRequests; - var batch = ""; - var i, len; - for (i = 0, len = batchParts.length; i < len; i++) { - batch += writeBatchPartDelimiter(batchBoundary, false) + - writeBatchPart(batchParts[i], context); - } - batch += writeBatchPartDelimiter(batchBoundary, true); - - // Register the boundary with the request content type. - var contentTypeProperties = context.contentType.properties; - contentTypeProperties.boundary = batchBoundary; - - return batch; -} - -/** Creates the delimiter that indicates that start or end of an individual request. - * @param {String} boundary Boundary string used to indicate the start of the request</param> - * @param {Boolean} close - Flag indicating that a close delimiter string should be generated - * @returns {String} Delimiter string - */ -function writeBatchPartDelimiter(boundary, close) { - var result = "\r\n--" + boundary; - if (close) { - result += "--"; - } - - return result + "\r\n"; -} - -/** Serializes a part of a batch request to a string. A part can be either a GET request or - * a change set grouping several CUD (create, update, delete) requests. - * @param part - Request or change set object in payload representation format</param> - * @param context - Object containing context information used for the serialization</param> - * @param {boolean} [nested] - - * @returns {String} String representing the serialized part - * A change set is an array of request objects and they cannot be nested inside other change sets. - */ -function writeBatchPart(part, context, nested) { - - - var changeSet = part.__changeRequests; - var result; - if (isArray(changeSet)) { - if (nested) { - throw { message: "Not Supported: change set nested in other change set" }; - } - - var changeSetBoundary = createBoundary("changeset_"); - result = "Content-Type: " + batchMediaType + "; boundary=" + changeSetBoundary + "\r\n"; - var i, len; - for (i = 0, len = changeSet.length; i < len; i++) { - result += writeBatchPartDelimiter(changeSetBoundary, false) + - writeBatchPart(changeSet[i], context, true); - } - - result += writeBatchPartDelimiter(changeSetBoundary, true); - } else { - result = "Content-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\n"; - var partContext = extend({}, context); - partContext.handler = handler; - partContext.request = part; - partContext.contentType = null; - - prepareRequest(part, partHandler(context), partContext); - result += writeRequest(part); - } - - return result; -} - -/* Serializes a request object to a string. - * @param request - Request object to serialize</param> - * @returns {String} String representing the serialized request - */ -function writeRequest(request) { - var result = (request.method ? request.method : "GET") + " " + request.requestUri + " HTTP/1.1\r\n"; - for (var name in request.headers) { - if (request.headers[name]) { - result = result + name + ": " + request.headers[name] + "\r\n"; - } - } - - result += "\r\n"; - - if (request.body) { - result += request.body; - } - - return result; -} - - - -/** batchHandler (see {@link module:odata/batch~batchParser}) */ -exports.batchHandler = handler(batchParser, batchSerializer, batchMediaType, MAX_DATA_SERVICE_VERSION); -exports.batchSerializer = batchSerializer; -exports.writeRequest = writeRequest; \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/503b4417/odatajs/src/lib/odata/handler.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/handler.js b/odatajs/src/lib/odata/handler.js deleted file mode 100644 index cbd09c6..0000000 --- a/odatajs/src/lib/odata/handler.js +++ /dev/null @@ -1,284 +0,0 @@ -/* - * 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/handler */ - - -var utils = require('./../utils.js'); -var oDataUtils = require('./odatautils.js'); - -// Imports. -var assigned = utils.assigned; -var extend = utils.extend; -var trimString = utils.trimString; -var maxVersion = oDataUtils.maxVersion; -var MAX_DATA_SERVICE_VERSION = "4.0"; - -/** Parses a string into an object with media type and properties. - * @param {String} str - String with media type to parse. - * @return null if the string is empty; an object with 'mediaType' and a 'properties' dictionary otherwise. - */ -function contentType(str) { - - if (!str) { - return null; - } - - var contentTypeParts = str.split(";"); - var properties = {}; - - var i, len; - for (i = 1, len = contentTypeParts.length; i < len; i++) { - var contentTypeParams = contentTypeParts[i].split("="); - properties[trimString(contentTypeParams[0])] = contentTypeParams[1]; - } - - return { mediaType: trimString(contentTypeParts[0]), properties: properties }; -} - -/** Serializes an object with media type and properties dictionary into a string. - * @param contentType - Object with media type and properties dictionary to serialize. - * @return String representation of the media type object; undefined if contentType is null or undefined.</returns> - */ -function contentTypeToString(contentType) { - if (!contentType) { - return undefined; - } - - var result = contentType.mediaType; - var property; - for (property in contentType.properties) { - result += ";" + property + "=" + contentType.properties[property]; - } - return result; -} - -/** Creates an object that is going to be used as the context for the handler's parser and serializer. - * @param contentType - Object with media type and properties dictionary. - * @param {String} dataServiceVersion - String indicating the version of the protocol to use. - * @param context - Operation context. - * @param handler - Handler object that is processing a resquest or response. - * @return Context object.</returns> - */ -function createReadWriteContext(contentType, dataServiceVersion, context, handler) { - - var rwContext = {}; - extend(rwContext, context); - extend(rwContext, { - contentType: contentType, - dataServiceVersion: dataServiceVersion, - handler: handler - }); - - return rwContext; -} - -/** Sets a request header's value. If the header has already a value other than undefined, null or empty string, then this method does nothing. - * @param request - Request object on which the header will be set. - * @param {String} name - Header name. - * @param {String} value - Header value. - */ -function fixRequestHeader(request, name, value) { - if (!request) { - return; - } - - var headers = request.headers; - if (!headers[name]) { - headers[name] = value; - } -} - -/** Sets the DataServiceVersion header of the request if its value is not yet defined or of a lower version. - * @param request - Request object on which the header will be set. - * @param {String} version - Version value. - * If the request has already a version value higher than the one supplied the this function does nothing. - */ -function fixDataServiceVersionHeader(request, version) { - - if (request) { - var headers = request.headers; - var dsv = headers["OData-Version"]; - headers["OData-Version"] = dsv ? maxVersion(dsv, version) : version; - } -} - -/** Gets the value of a request or response header. - * @param requestOrResponse - Object representing a request or a response. - * @param {String} name - Name of the header to retrieve. - * @returns {String} String value of the header; undefined if the header cannot be found. - */ -function getRequestOrResponseHeader(requestOrResponse, name) { - - var headers = requestOrResponse.headers; - return (headers && headers[name]) || undefined; -} - -/** Gets the value of the Content-Type header from a request or response. - * @param requestOrResponse - Object representing a request or a response. - * @returns {Object} Object with 'mediaType' and a 'properties' dictionary; null in case that the header is not found or doesn't have a value. - */ -function getContentType(requestOrResponse) { - - return contentType(getRequestOrResponseHeader(requestOrResponse, "Content-Type")); -} - -var versionRE = /^\s?(\d+\.\d+);?.*$/; -/** Gets the value of the DataServiceVersion header from a request or response. - * @param requestOrResponse - Object representing a request or a response. - * @returns {String} Data service version; undefined if the header cannot be found. - */ -function getDataServiceVersion(requestOrResponse) { - - var value = getRequestOrResponseHeader(requestOrResponse, "OData-Version"); - if (value) { - var matches = versionRE.exec(value); - if (matches && matches.length) { - return matches[1]; - } - } - - // Fall through and return undefined. -} - -/** Checks that a handler can process a particular mime type. - * @param handler - Handler object that is processing a resquest or response. - * @param cType - Object with 'mediaType' and a 'properties' dictionary. - * @returns {Boolean} True if the handler can process the mime type; false otherwise. - * - * The following check isn't as strict because if cType.mediaType = application/; it will match an accept value of "application/xml"; - * however in practice we don't not expect to see such "suffixed" mimeTypes for the handlers. - */ -function handlerAccepts(handler, cType) { - return handler.accept.indexOf(cType.mediaType) >= 0; -} - -/** Invokes the parser associated with a handler for reading the payload of a HTTP response. - * @param handler - Handler object that is processing the response. - * @param {Function} parseCallback - Parser function that will process the response payload. - * @param response - HTTP response whose payload is going to be processed. - * @param context - Object used as the context for processing the response. - * @returns {Boolean} True if the handler processed the response payload and the response.data property was set; false otherwise. - */ -function handlerRead(handler, parseCallback, response, context) { - - if (!response || !response.headers) { - return false; - } - - var cType = getContentType(response); - var version = getDataServiceVersion(response) || ""; - var body = response.body; - - if (!assigned(body)) { - return false; - } - - if (handlerAccepts(handler, cType)) { - var readContext = createReadWriteContext(cType, version, context, handler); - readContext.response = response; - response.data = parseCallback(handler, body, readContext); - return response.data !== undefined; - } - - return false; -} - -/** Invokes the serializer associated with a handler for generating the payload of a HTTP request. - * @param handler - Handler object that is processing the request. - * @param {Function} serializeCallback - Serializer function that will generate the request payload. - * @param response - HTTP request whose payload is going to be generated. - * @param context - Object used as the context for serializing the request. - * @returns {Boolean} True if the handler serialized the request payload and the request.body property was set; false otherwise. - */ -function handlerWrite(handler, serializeCallback, request, context) { - if (!request || !request.headers) { - return false; - } - - var cType = getContentType(request); - var version = getDataServiceVersion(request); - - if (!cType || handlerAccepts(handler, cType)) { - var writeContext = createReadWriteContext(cType, version, context, handler); - writeContext.request = request; - - request.body = serializeCallback(handler, request.data, writeContext); - - if (request.body !== undefined) { - fixDataServiceVersionHeader(request, writeContext.dataServiceVersion || "4.0"); - - fixRequestHeader(request, "Content-Type", contentTypeToString(writeContext.contentType)); - fixRequestHeader(request, "OData-MaxVersion", handler.maxDataServiceVersion); - return true; - } - } - - return false; -} - -/** Creates a handler object for processing HTTP requests and responses. - * @param {Function} parseCallback - Parser function that will process the response payload. - * @param {Function} serializeCallback - Serializer function that will generate the request payload. - * @param {String} accept - String containing a comma separated list of the mime types that this handler can work with. - * @param {String} maxDataServiceVersion - String indicating the highest version of the protocol that this handler can work with. - * @returns {Object} Handler object. - */ -function handler(parseCallback, serializeCallback, accept, maxDataServiceVersion) { - - return { - accept: accept, - maxDataServiceVersion: maxDataServiceVersion, - - read: function (response, context) { - return handlerRead(this, parseCallback, response, context); - }, - - write: function (request, context) { - return handlerWrite(this, serializeCallback, request, context); - } - }; -} - -function textParse(handler, body /*, context */) { - return body; -} - -function textSerialize(handler, data /*, context */) { - if (assigned(data)) { - return data.toString(); - } else { - return undefined; - } -} - - - - -exports.textHandler = handler(textParse, textSerialize, "text/plain", MAX_DATA_SERVICE_VERSION); - -exports.contentType = contentType; -exports.contentTypeToString = contentTypeToString; -exports.handler = handler; -exports.createReadWriteContext = createReadWriteContext; -exports.fixRequestHeader = fixRequestHeader; -exports.getRequestOrResponseHeader = getRequestOrResponseHeader; -exports.getContentType = getContentType; -exports.getDataServiceVersion = getDataServiceVersion; -exports.MAX_DATA_SERVICE_VERSION = MAX_DATA_SERVICE_VERSION; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/503b4417/odatajs/src/lib/odata/json.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/json.js b/odatajs/src/lib/odata/json.js deleted file mode 100644 index 6a6968a..0000000 --- a/odatajs/src/lib/odata/json.js +++ /dev/null @@ -1,917 +0,0 @@ -/* - * 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 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 XXXparseDateTime = oDataUtils.XXXparseDateTime; - -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); - - -// The regular expression corresponds to something like this: -// /Date(123+60)/ -// -// This first number is date ticks, the + may be a - and is optional, -// with the second number indicating a timezone offset in minutes. -// -// On the wire, the leading and trailing forward slashes are -// escaped without being required to so the chance of collisions is reduced; -// however, by the time we see the objects, the characters already -// look like regular forward slashes. -var jsonDateRE = /^\/Date\((-?\d+)(\+|-)?(\d+)?\)\/$/; - -/** Formats the given minutes into (+/-)hh:mm format. - * @param {Number} minutes - Number of minutes to format. - * @returns {String} The minutes in (+/-)hh:mm format. - */ -function minutesToOffset(minutes) { - - var sign; - if (minutes < 0) { - sign = "-"; - minutes = -minutes; - } else { - sign = "+"; - } - - var hours = Math.floor(minutes / 60); - minutes = minutes - (60 * hours); - - return sign + formatNumberWidth(hours, 2) + ":" + formatNumberWidth(minutes, 2); -} - -/** Parses the JSON Date representation into a Date object. - * @param {String} value - String value. - * @returns {Date} A Date object if the value matches one; falsy otherwise. - */ -function parseJsonDateString(value) { - - var arr = value && jsonDateRE.exec(value); - if (arr) { - // 0 - complete results; 1 - ticks; 2 - sign; 3 - minutes - var result = new Date(parseInt10(arr[1])); - if (arr[2]) { - var mins = parseInt10(arr[3]); - if (arr[2] === "-") { - mins = -mins; - } - - // The offset is reversed to get back the UTC date, which is - // what the API will eventually have. - var current = result.getUTCMinutes(); - result.setUTCMinutes(current - mins); - result.__edmType = "Edm.DateTimeOffset"; - result.__offset = minutesToOffset(mins); - } - if (!isNaN(result.valueOf())) { - return result; - } - } - - // Allow undefined to be returned. -} - -// Some JSON implementations cannot produce the character sequence \/ -// which is needed to format DateTime and DateTimeOffset into the -// JSON string representation defined by the OData protocol. -// See the history of this file for a candidate implementation of -// a 'formatJsonDateString' function. - -/** Parses a JSON OData payload. - * @param handler - This handler. - * @param text - Payload text (this parser also handles pre-parsed objects). - * @param {Object} context - Object with parsing context. - * @return An object representation of the OData payload.</returns> - */ -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 readPayloadMinimal(json, model, recognizeDates); - } - else if (payloadFormat === 2) { - // to do: using the EDM Model to get the type of each property instead of just guessing. - return readPayloadFull(json, model, recognizeDates); - } - else { - return json; - } -} - - -function addType(data, name, value ) { - var fullName = name + '@odata.type'; - - if ( data[fullName] === undefined) { - data[fullName] = '#' + value; - } -} - -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; - } - - } -} - -function addTypeColNoEdm(data, name, value ) { - var fullName = name + '@odata.type'; - - if ( data[fullName] === undefined) { - if ( value.substring(0,4)==='Edm.') { - data[fullName] = '#Collection('+value.substring(4)+ ')'; - } else { - data[fullName] = '#Collection('+value+ ')'; - } - } -} - - -/* Adds typeinformation for String, Boolean and numerical EDM-types. - * The type is determined from the odata-json-format-v4.0.doc specification - * @param data - Date which will be extendet - * @param {Boolean} recognizeDates - True if strings formatted as datetime values should be treated as datetime values. False otherwise. - * @returns An object representation of the OData payload. - */ -function readPayloadFull(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) { - readPayloadFull(data[key][i], model, recognizeDates); - } - } else if (utils.isObject(data[key])) { - if (data[key] !== null) { - //don't step into geo.. objects - var isGeo = false; - type = data[key+'@odata.type']; - if (type && (isGeographyEdmType(type) || isGeometryEdmType(type))) { - // is gemometry type - } else { - readPayloadFull(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; -} - -/** Serializes the data by returning its string representation. - * @param handler - This handler. - * @param data - Data to serialize. - * @param {Object} context - Object with serialization context. - * @returns {String} The string representation of data. - */ -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); - } - } - - return undefined; -} - -function formatJsonRequestPayload(data) { - if (!data) { - return data; - } - - if (isPrimitive(data)) { - return data; - } - - if (isArray(data)) { - var newArrayData = []; - var i, len; - for (i = 0, len = data.length; i < len; i++) { - newArrayData[i] = formatJsonRequestPayload(data[i]); - } - - return newArrayData; - } - - var newdata = {}; - for (var property in data) { - if (isJsonSerializableProperty(property)) { - newdata[property] = formatJsonRequestPayload(data[property]); - } - } - - return newdata; -} - -/** JSON replacer function for converting a value to its JSON representation. - * @param {Object} value - Value to convert.</param> - * @returns {String} JSON representation of the input value. - * This method is used during JSON serialization and invoked only by the JSON.stringify function. - * It should never be called directly. - */ -function jsonReplacer(_, value) { - - - if (value && value.__edmType === "Edm.Time") { - return formatDuration(value); - } else { - return value; - } -} - - -/** Creates an object containing information for the json payload. - * @param {String} kind - JSON payload kind, one of the PAYLOADTYPE_XXX constant values. - * @param {String} typeName - Type name of the JSON payload. - * @returns {Object} Object with kind and type fields. - */ -function jsonMakePayloadInfo(kind, type) { - - /// TODO docu - /// <field name="kind" type="String">Kind of the JSON payload. One of the PAYLOADTYPE_XXX constant values.</field> - /// <field name="type" type="String">Data type of the JSON payload.</field> - - return { kind: kind, type: type || null }; -} - -/** Creates an object containing information for the context - * TODO check dou layout - * @returns {Object} Object with type information - * @returns {Object.detectedPayloadKind(optional)} see constants starting with PAYLOADTYPE_ - * @returns {Object.deltaKind(optional)} deltainformation, one of the following valus DELTATYPE_FEED | DELTATYPE_DELETED_ENTRY | DELTATYPE_LINK | DELTATYPE_DELETED_LINK - * @returns {Object.typeName(optional)} name of the type - * @returns {Object.type(optional)} object containing type information for entity- and complex-types ( null if a typeName is a primitive) -*/ -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); -} - -/** Processe a JSON response payload with metadata-minimal - * @param {Object} data - Json response payload object - * @param {Object} model - Object describing an OData conceptual schema - * @param {Boolean} recognizeDates - Flag indicating whether datetime literal strings should be converted to JavaScript Date objects. - * @returns {Object} Object in the library's representation. - */ -function readPayloadMinimal(data, model, recognizeDates) { - - if (!assigned(model) || isArray(model)) { - return data; - } - - var baseURI = data[contextUrlAnnotation]; - var payloadInfo = createPayloadInfo(data, model); - - switch (payloadInfo.detectedPayloadKind) { - case PAYLOADTYPE_VALUE: - return readPayloadMinimalProperty(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_FEED: - return readPayloadMinimalFeed(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_ENTRY: - return readPayloadMinimalEntry(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_COLLECTION: - return readPayloadMinimalCollection(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_PROPERTY: - return readPayloadMinimalProperty(data, model, payloadInfo, baseURI, recognizeDates); - case PAYLOADTYPE_SVCDOC: - return data; - case PAYLOADTYPE_LINKS: - return data; - } - - return data; -} - -/** Gets the key of an entry. - * @param {Object} data - JSON entry. - * - * @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; -} - -function readPayloadMinimalProperty(data, model, collectionInfo, baseURI, recognizeDates) { - if (collectionInfo.type !== null) { - readPayloadMinimalObject(data, collectionInfo, baseURI, model, recognizeDates); - } else { - addTypeNoEdm(data,'value', collectionInfo.typeName); - //data['[email protected]'] = '#'+collectionInfo.typeName; - } - return data; -} - -function readPayloadMinimalCollection(data, model, collectionInfo, baseURI, recognizeDates) { - //data['@odata.type'] = '#Collection('+collectionInfo.typeName + ')'; - addTypeColNoEdm(data,'', collectionInfo.typeName); - - if (collectionInfo.type !== null) { - var entries = []; - - var items = data.value; - for (i = 0, len = items.length; i < len; i++) { - var item = items[i]; - if ( defined(item['@odata.type'])) { // in case of mixed collections - var typeName = item['@odata.type'].substring(1); - var type = lookupEntityType( typeName, model); - var entryInfo = { - contentTypeOdata : collectionInfo.contentTypeOdata, - detectedPayloadKind : collectionInfo.detectedPayloadKind, - name : collectionInfo.name, - type : type, - typeName : typeName - }; - - entry = readPayloadMinimalObject(item, entryInfo, baseURI, model, recognizeDates); - } else { - entry = readPayloadMinimalObject(item, collectionInfo, baseURI, model, recognizeDates); - } - - entries.push(entry); - } - data.value = entries; - } - return data; -} - -function readPayloadMinimalFeed(data, model, feedInfo, baseURI, recognizeDates) { - var entries = []; - var items = data.value; - for (i = 0, len = items.length; i < len; i++) { - var item = items[i]; - if ( defined(item['@odata.type'])) { // in case of mixed feeds - var typeName = item['@odata.type'].substring(1); - var type = lookupEntityType( typeName, model); - var entryInfo = { - contentTypeOdata : feedInfo.contentTypeOdata, - detectedPayloadKind : feedInfo.detectedPayloadKind, - name : feedInfo.name, - type : type, - typeName : typeName - }; - - entry = readPayloadMinimalObject(item, entryInfo, baseURI, model, recognizeDates); - } else { - entry = readPayloadMinimalObject(item, feedInfo, baseURI, model, recognizeDates); - } - - entries.push(entry); - } - data.value = entries; - return data; -} - -function readPayloadMinimalEntry(data, model, entryInfo, baseURI, recognizeDates) { - return readPayloadMinimalObject(data, entryInfo, baseURI, model, recognizeDates); -} - -/** Formats a value according to Uri literal format - * @param value - Value to be formatted. - * @param type - Edm type of the value - * @returns {string} Value after formatting - */ -function formatLiteral(value, type) { - - value = "" + formatRowLiteral(value, type); - value = encodeURIComponent(value.replace("'", "''")); - switch ((type)) { - case "Edm.Binary": - return "X'" + value + "'"; - case "Edm.DateTime": - return "datetime" + "'" + value + "'"; - case "Edm.DateTimeOffset": - return "datetimeoffset" + "'" + value + "'"; - case "Edm.Decimal": - return value + "M"; - case "Edm.Guid": - return "guid" + "'" + value + "'"; - case "Edm.Int64": - return value + "L"; - case "Edm.Float": - return value + "f"; - case "Edm.Double": - return value + "D"; - case "Edm.Geography": - return "geography" + "'" + value + "'"; - case "Edm.Geometry": - return "geometry" + "'" + value + "'"; - case "Edm.Time": - return "time" + "'" + value + "'"; - case "Edm.String": - return "'" + value + "'"; - default: - return value; - } -} - -function formatRowLiteral(value, type) { - switch (type) { - case "Edm.Binary": - return convertByteArrayToHexString(value); - default: - return value; - } -} - -function convertDates(data, propertyName,type) { - if (type === 'Edm.Date') { - data[propertyName] = oDataUtils.parseDate(data[propertyName], true); - } else if (type === 'Edm.DateTimeOffset') { - data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true); - } else if (type === 'Edm.Duration') { - data[propertyName] = oDataUtils.parseDuration(data[propertyName], true); - } else if (type === 'Edm.Time') { - data[propertyName] = oDataUtils.parseTime(data[propertyName], true); - } -} - -function convertDatesNoEdm(data, propertyName,type) { - if (type === 'Date') { - data[propertyName] = oDataUtils.parseDate(data[propertyName], true); - } else if (type === 'DateTimeOffset') { - data[propertyName] = oDataUtils.parseDateTimeOffset(data[propertyName], true); - } else if (type === 'Duration') { - data[propertyName] = oDataUtils.parseDuration(data[propertyName], true); - } else if (type === 'Time') { - data[propertyName] = oDataUtils.parseTime(data[propertyName], true); - } -} - -function checkProperties(data, objectInfoType, baseURI, model, recognizeDates) { - for (var name in data) { - if (name.indexOf("@") === -1) { - var curType = objectInfoType; - var propertyValue = data[name]; - var property = lookupProperty(curType.property,name); //TODO SK add check for parent type - - while (( property === null) && (curType.baseType !== undefined)) { - curType = lookupEntityType(curType.baseType, model); - property = lookupProperty(curType.property,name); - } - - if ( isArray(propertyValue)) { - //data[name+'@odata.type'] = '#' + property.type; - if (isCollectionType(property.type)) { - addTypeColNoEdm(data,name,property.type.substring(11,property.type.length-1)); - } else { - addTypeNoEdm(data,name,property.type); - } - - - for ( var i = 0; i < propertyValue.length; i++) { - readPayloadMinimalComplexObject(propertyValue[i], property, baseURI, model, recognizeDates); - } - } else if (isObject(propertyValue) && (propertyValue !== null)) { - readPayloadMinimalComplexObject(propertyValue, property, baseURI, model, recognizeDates); - } else { - //data[name+'@odata.type'] = '#' + property.type; - addTypeNoEdm(data,name,property.type); - if (recognizeDates) { - convertDates(data, name, property.type); - } - } - } - } -} - -function readPayloadMinimalComplexObject(data, property, baseURI, model, recognizeDates) { - var type = property.type; - if (isCollectionType(property.type)) { - type =property.type.substring(11,property.type.length-1); - } - - //data['@odata.type'] = '#'+type; - addType(data,'',property.type); - - - var propertyType = lookupComplexType(type, model); - if (propertyType === null) { - return; //TODO check what to do if the type is not known e.g. type #GeometryCollection - } - - checkProperties(data, propertyType, baseURI, model, recognizeDates); -} - -function readPayloadMinimalObject(data, objectInfo, baseURI, model, recognizeDates) { - //data['@odata.type'] = '#'+objectInfo.typeName; - addType(data,'',objectInfo.typeName); - - var keyType = objectInfo.type; - while ((defined(keyType)) && ( keyType.key === undefined) && (keyType.baseType !== undefined)) { - keyType = lookupEntityType(keyType.baseType, model); - } - - //if ((keyType !== undefined) && (keyType.key !== undefined)) { - if (keyType.key !== undefined) { - var lastIdSegment = objectInfo.name + jsonGetEntryKey(data, keyType); - data['@odata.id'] = baseURI.substring(0, baseURI.lastIndexOf("$metadata")) + lastIdSegment; - data['@odata.editLink'] = lastIdSegment; - } - - var serviceURI = baseURI.substring(0, baseURI.lastIndexOf("$metadata")); - //json ComputeUrisIfMissing(data, entryInfo, actualType, serviceURI, dataModel, baseTypeModel); - - checkProperties(data, objectInfo.type, baseURI, model, recognizeDates); - - return data; -} - -var jsonSerializableMetadata = ["@odata.id", "@odata.type"]; - -function isJsonSerializableProperty(property) { - if (!property) { - return false; - } - - if (property.indexOf("@odata.") == -1) { - return true; - } - - var i, len; - for (i = 0, len = jsonSerializableMetadata.length; i < len; i++) { - var name = jsonSerializableMetadata[i]; - if (property.indexOf(name) != -1) { - return true; - } - } - - return false; -} - -/** Determines whether a type name is a primitive type in a JSON payload. - * @param {String} typeName - Type name to test. - * @returns {Boolean} True if the type name an EDM primitive type or an OData spatial type; false otherwise. - */ -function jsonIsPrimitiveType(typeName) { - - return isPrimitiveEdmType(typeName) || isGeographyEdmType(typeName) || isGeometryEdmType(typeName); -} - - -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; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/503b4417/odatajs/src/lib/odata/metadata.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/metadata.js b/odatajs/src/lib/odata/metadata.js deleted file mode 100644 index e37161f..0000000 --- a/odatajs/src/lib/odata/metadata.js +++ /dev/null @@ -1,523 +0,0 @@ -/* - * 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/metadata */ - -var utils = require('./../utils.js'); -var oDSxml = require('./../xml.js'); -var odataHandler = require('./handler.js'); - - - -// imports -var contains = utils.contains; -var normalizeURI = utils.normalizeURI; -var xmlAttributes = oDSxml.xmlAttributes; -var xmlChildElements = oDSxml.xmlChildElements; -var xmlFirstChildElement = oDSxml.xmlFirstChildElement; -var xmlInnerText = oDSxml.xmlInnerText; -var xmlLocalName = oDSxml.xmlLocalName; -var xmlNamespaceURI = oDSxml.xmlNamespaceURI; -var xmlNS = oDSxml.xmlNS; -var xmlnsNS = oDSxml.xmlnsNS; -var xmlParse = oDSxml.xmlParse; - -var ado = oDSxml.http + "docs.oasis-open.org/odata/"; // http://docs.oasis-open.org/odata/ -var adoDs = ado + "ns"; // http://docs.oasis-open.org/odata/ns -var edmxNs = adoDs + "/edmx"; // http://docs.oasis-open.org/odata/ns/edmx -var edmNs1 = adoDs + "/edm"; // http://docs.oasis-open.org/odata/ns/edm -var odataMetaXmlNs = adoDs + "/metadata"; // http://docs.oasis-open.org/odata/ns/metadata -var MAX_DATA_SERVICE_VERSION = odataHandler.MAX_DATA_SERVICE_VERSION; - -var xmlMediaType = "application/xml"; - -/** Creates an object that describes an element in an schema. - * @param {Array} attributes - List containing the names of the attributes allowed for this element. - * @param {Array} elements - List containing the names of the child elements allowed for this element. - * @param {Boolean} text - Flag indicating if the element's text value is of interest or not. - * @param {String} ns - Namespace to which the element belongs to. - * If a child element name ends with * then it is understood by the schema that that child element can appear 0 or more times. - * @returns {Object} Object with attributes, elements, text, and ns fields. - */ -function schemaElement(attributes, elements, text, ns) { - - return { - attributes: attributes, - elements: elements, - text: text || false, - ns: ns - }; -} - -// It's assumed that all elements may have Documentation children and Annotation elements. -// See http://docs.oasis-open.org/odata/odata/v4.0/cs01/part3-csdl/odata-v4.0-cs01-part3-csdl.html for a CSDL reference. -var schema = { - elements: { - Action: schemaElement( - /*attributes*/["Name", "IsBound", "EntitySetPath"], - /*elements*/["ReturnType", "Parameter*", "Annotation*"] - ), - ActionImport: schemaElement( - /*attributes*/["Name", "Action", "EntitySet", "Annotation*"] - ), - Annotation: schemaElement( - /*attributes*/["Term", "Qualifier", "Binary", "Bool", "Date", "DateTimeOffset", "Decimal", "Duration", "EnumMember", "Float", "Guid", "Int", "String", "TimeOfDay", "AnnotationPath", "NavigationPropertyPath", "Path", "PropertyPath", "UrlRef"], - /*elements*/["Binary*", "Bool*", "Date*", "DateTimeOffset*", "Decimal*", "Duration*", "EnumMember*", "Float*", "Guid*", "Int*", "String*", "TimeOfDay*", "And*", "Or*", "Not*", "Eq*", "Ne*", "Gt*", "Ge*", "Lt*", "Le*", "AnnotationPath*", "Apply*", "Cast*", "Collection*", "If*", "IsOf*", "LabeledElement*", "LabeledElementReference*", "Null*", "NavigationPropertyPath*", "Path*", "PropertyPath*", "Record*", "UrlRef*", "Annotation*"] - ), - AnnotationPath: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Annotations: schemaElement( - /*attributes*/["Target", "Qualifier"], - /*elements*/["Annotation*"] - ), - Apply: schemaElement( - /*attributes*/["Function"], - /*elements*/["String*", "Path*", "LabeledElement*", "Annotation*"] - ), - And: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Or: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Not: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Eq: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Ne: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Gt: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Ge: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Lt: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Le: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Binary: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Bool: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Cast: schemaElement( - /*attributes*/["Type"], - /*elements*/["Path*", "Annotation*"] - ), - Collection: schemaElement( - /*attributes*/null, - /*elements*/["Binary*", "Bool*", "Date*", "DateTimeOffset*", "Decimal*", "Duration*", "EnumMember*", "Float*", "Guid*", "Int*", "String*", "TimeOfDay*", "And*", "Or*", "Not*", "Eq*", "Ne*", "Gt*", "Ge*", "Lt*", "Le*", "AnnotationPath*", "Apply*", "Cast*", "Collection*", "If*", "IsOf*", "LabeledElement*", "LabeledElementReference*", "Null*", "NavigationPropertyPath*", "Path*", "PropertyPath*", "Record*", "UrlRef*"] - ), - ComplexType: schemaElement( - /*attributes*/["Name", "BaseType", "Abstract", "OpenType"], - /*elements*/["Property*", "NavigationProperty*", "Annotation*"] - ), - Date: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - DateTimeOffset: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Decimal: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Duration: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - EntityContainer: schemaElement( - /*attributes*/["Name", "Extends"], - /*elements*/["EntitySet*", "Singleton*", "ActionImport*", "FunctionImport*", "Annotation*"] - ), - EntitySet: schemaElement( - /*attributes*/["Name", "EntityType", "IncludeInServiceDocument"], - /*elements*/["NavigationPropertyBinding*", "Annotation*"] - ), - EntityType: schemaElement( - /*attributes*/["Name", "BaseType", "Abstract", "OpenType", "HasStream"], - /*elements*/["Key*", "Property*", "NavigationProperty*", "Annotation*"] - ), - EnumMember: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - EnumType: schemaElement( - /*attributes*/["Name", "UnderlyingType", "IsFlags"], - /*elements*/["Member*"] - ), - Float: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Function: schemaElement( - /*attributes*/["Name", "IsBound", "IsComposable", "EntitySetPath"], - /*elements*/["ReturnType", "Parameter*", "Annotation*"] - ), - FunctionImport: schemaElement( - /*attributes*/["Name", "Function", "EntitySet", "IncludeInServiceDocument", "Annotation*"] - ), - Guid: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - If: schemaElement( - /*attributes*/null, - /*elements*/["Path*", "String*", "Annotation*"] - ), - Int: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - IsOf: schemaElement( - /*attributes*/["Type", "MaxLength", "Precision", "Scale", "Unicode", "SRID", "DefaultValue", "Annotation*"], - /*elements*/["Path*"] - ), - Key: schemaElement( - /*attributes*/null, - /*elements*/["PropertyRef*"] - ), - LabeledElement: schemaElement( - /*attributes*/["Name"], - /*elements*/["Binary*", "Bool*", "Date*", "DateTimeOffset*", "Decimal*", "Duration*", "EnumMember*", "Float*", "Guid*", "Int*", "String*", "TimeOfDay*", "And*", "Or*", "Not*", "Eq*", "Ne*", "Gt*", "Ge*", "Lt*", "Le*", "AnnotationPath*", "Apply*", "Cast*", "Collection*", "If*", "IsOf*", "LabeledElement*", "LabeledElementReference*", "Null*", "NavigationPropertyPath*", "Path*", "PropertyPath*", "Record*", "UrlRef*", "Annotation*"] - ), - LabeledElementReference: schemaElement( - /*attributes*/["Term"], - /*elements*/["Binary*", "Bool*", "Date*", "DateTimeOffset*", "Decimal*", "Duration*", "EnumMember*", "Float*", "Guid*", "Int*", "String*", "TimeOfDay*", "And*", "Or*", "Not*", "Eq*", "Ne*", "Gt*", "Ge*", "Lt*", "Le*", "AnnotationPath*", "Apply*", "Cast*", "Collection*", "If*", "IsOf*", "LabeledElement*", "LabeledElementReference*", "Null*", "NavigationPropertyPath*", "Path*", "PropertyPath*", "Record*", "UrlRef*"] - ), - Member: schemaElement( - /*attributes*/["Name", "Value"], - /*element*/["Annotation*"] - ), - NavigationProperty: schemaElement( - /*attributes*/["Name", "Type", "Nullable", "Partner", "ContainsTarget"], - /*elements*/["ReferentialConstraint*", "OnDelete*", "Annotation*"] - ), - NavigationPropertyBinding: schemaElement( - /*attributes*/["Path", "Target"] - ), - NavigationPropertyPath: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Null: schemaElement( - /*attributes*/null, - /*elements*/["Annotation*"] - ), - OnDelete: schemaElement( - /*attributes*/["Action"], - /*elements*/["Annotation*"] - ), - Path: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Parameter: schemaElement( - /*attributes*/["Name", "Type", "Nullable", "MaxLength", "Precision", "Scale", "SRID"], - /*elements*/["Annotation*"] - ), - Property: schemaElement( - /*attributes*/["Name", "Type", "Nullable", "MaxLength", "Precision", "Scale", "Unicode", "SRID", "DefaultValue"], - /*elements*/["Annotation*"] - ), - PropertyPath: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - PropertyRef: schemaElement( - /*attributes*/["Name", "Alias"] - ), - PropertyValue: schemaElement( - /*attributes*/["Property", "Path"], - /*elements*/["Binary*", "Bool*", "Date*", "DateTimeOffset*", "Decimal*", "Duration*", "EnumMember*", "Float*", "Guid*", "Int*", "String*", "TimeOfDay*", "And*", "Or*", "Not*", "Eq*", "Ne*", "Gt*", "Ge*", "Lt*", "Le*", "AnnotationPath*", "Apply*", "Cast*", "Collection*", "If*", "IsOf*", "LabeledElement*", "LabeledElementReference*", "Null*", "NavigationPropertyPath*", "Path*", "PropertyPath*", "Record*", "UrlRef*", "Annotation*"] - ), - Record: schemaElement( - /*attributes*/null, - /*Elements*/["PropertyValue*", "Property*", "Annotation*"] - ), - ReferentialConstraint: schemaElement( - /*attributes*/["Property", "ReferencedProperty", "Annotation*"] - ), - ReturnType: schemaElement( - /*attributes*/["Type", "Nullable", "MaxLength", "Precision", "Scale", "SRID"] - ), - String: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - Schema: schemaElement( - /*attributes*/["Namespace", "Alias"], - /*elements*/["Action*", "Annotations*", "Annotation*", "ComplexType*", "EntityContainer", "EntityType*", "EnumType*", "Function*", "Term*", "TypeDefinition*", "Annotation*"] - ), - Singleton: schemaElement( - /*attributes*/["Name", "Type"], - /*elements*/["NavigationPropertyBinding*", "Annotation*"] - ), - Term: schemaElement( - /*attributes*/["Name", "Type", "BaseTerm", "DefaultValue ", "AppliesTo", "Nullable", "MaxLength", "Precision", "Scale", "SRID"], - /*elements*/["Annotation*"] - ), - TimeOfDay: schemaElement( - /*attributes*/null, - /*elements*/null, - /*text*/true - ), - TypeDefinition: schemaElement( - /*attributes*/["Name", "UnderlyingType", "MaxLength", "Unicode", "Precision", "Scale", "SRID"], - /*elements*/["Annotation*"] - ), - UrlRef: schemaElement( - /*attributes*/null, - /*elements*/["Binary*", "Bool*", "Date*", "DateTimeOffset*", "Decimal*", "Duration*", "EnumMember*", "Float*", "Guid*", "Int*", "String*", "TimeOfDay*", "And*", "Or*", "Not*", "Eq*", "Ne*", "Gt*", "Ge*", "Lt*", "Le*", "AnnotationPath*", "Apply*", "Cast*", "Collection*", "If*", "IsOf*", "LabeledElement*", "LabeledElementReference*", "Null*", "NavigationPropertyPath*", "Path*", "PropertyPath*", "Record*", "UrlRef*", "Annotation*"] - ), - - // See http://msdn.microsoft.com/en-us/library/dd541238(v=prot.10) for an EDMX reference. - Edmx: schemaElement( - /*attributes*/["Version"], - /*elements*/["DataServices", "Reference*"], - /*text*/false, - /*ns*/edmxNs - ), - DataServices: schemaElement( - /*attributes*/["m:MaxDataServiceVersion", "m:DataServiceVersion"], - /*elements*/["Schema*"], - /*text*/false, - /*ns*/edmxNs - ), - Reference: schemaElement( - /*attributes*/["Uri"], - /*elements*/["Include*", "IncludeAnnotations*", "Annotation*"] - ), - Include: schemaElement( - /*attributes*/["Namespace", "Alias"] - ), - IncludeAnnotations: schemaElement( - /*attributes*/["TermNamespace", "Qualifier", "TargetNamespace"] - ) - } -}; - - -/** Converts a Pascal-case identifier into a camel-case identifier. - * @param {String} text - Text to convert. - * @returns {String} Converted text. - * If the text starts with multiple uppercase characters, it is left as-is.</remarks> - */ -function scriptCase(text) { - - if (!text) { - return text; - } - - if (text.length > 1) { - var firstTwo = text.substr(0, 2); - if (firstTwo === firstTwo.toUpperCase()) { - return text; - } - - return text.charAt(0).toLowerCase() + text.substr(1); - } - - return text.charAt(0).toLowerCase(); -} - -/** Gets the schema node for the specified element. - * @param {Object} parentSchema - Schema of the parent XML node of 'element'. - * @param candidateName - XML element name to consider. - * @returns {Object} The schema that describes the specified element; null if not found. - */ -function getChildSchema(parentSchema, candidateName) { - - var elements = parentSchema.elements; - if (!elements) { - return null; - } - - var i, len; - for (i = 0, len = elements.length; i < len; i++) { - var elementName = elements[i]; - var multipleElements = false; - if (elementName.charAt(elementName.length - 1) === "*") { - multipleElements = true; - elementName = elementName.substr(0, elementName.length - 1); - } - - if (candidateName === elementName) { - var propertyName = scriptCase(elementName); - return { isArray: multipleElements, propertyName: propertyName }; - } - } - - return null; -} - -/** Checks whether the specifies namespace URI is one of the known CSDL namespace URIs. - * @param {String} nsURI - Namespace URI to check. - * @returns {Boolean} true if nsURI is a known CSDL namespace; false otherwise. - */ -function isEdmNamespace(nsURI) { - - return nsURI === edmNs1; -} - -/** Parses a CSDL document. - * @param element - DOM element to parse. - * @returns {Object} An object describing the parsed element. - */ -function parseConceptualModelElement(element) { - - var localName = xmlLocalName(element); - var nsURI = xmlNamespaceURI(element); - var elementSchema = schema.elements[localName]; - if (!elementSchema) { - return null; - } - - if (elementSchema.ns) { - if (nsURI !== elementSchema.ns) { - return null; - } - } else if (!isEdmNamespace(nsURI)) { - return null; - } - - var item = {}; - var attributes = elementSchema.attributes || []; - xmlAttributes(element, function (attribute) { - - var localName = xmlLocalName(attribute); - var nsURI = xmlNamespaceURI(attribute); - var value = attribute.value; - - // Don't do anything with xmlns attributes. - if (nsURI === xmlnsNS) { - return; - } - - // Currently, only m: for metadata is supported as a prefix in the internal schema table, - // un-prefixed element names imply one a CSDL element. - var schemaName = null; - var handled = false; - if (isEdmNamespace(nsURI) || nsURI === null) { - schemaName = ""; - } else if (nsURI === odataMetaXmlNs) { - schemaName = "m:"; - } - - if (schemaName !== null) { - schemaName += localName; - - if (contains(attributes, schemaName)) { - item[scriptCase(localName)] = value; - } - } - - }); - - xmlChildElements(element, function (child) { - var localName = xmlLocalName(child); - var childSchema = getChildSchema(elementSchema, localName); - if (childSchema) { - if (childSchema.isArray) { - var arr = item[childSchema.propertyName]; - if (!arr) { - arr = []; - item[childSchema.propertyName] = arr; - } - arr.push(parseConceptualModelElement(child)); - } else { - item[childSchema.propertyName] = parseConceptualModelElement(child); - } - } - }); - - if (elementSchema.text) { - item.text = xmlInnerText(element); - } - - return item; -} - -/** Parses a metadata document. - * @param handler - This handler. - * @param {String} text - Metadata text. - * @returns An object representation of the conceptual model.</returns> - */ -function metadataParser(handler, text) { - - var doc = xmlParse(text); - var root = xmlFirstChildElement(doc); - return parseConceptualModelElement(root) || undefined; -} - - - -exports.metadataHandler = odataHandler.handler(metadataParser, null, xmlMediaType, MAX_DATA_SERVICE_VERSION); - -exports.schema = schema; -exports.scriptCase = scriptCase; -exports.getChildSchema = getChildSchema; -exports.parseConceptualModelElement = parseConceptualModelElement; -exports.metadataParser = metadataParser; \ No newline at end of file
