Repository: olingo-odata4-js Updated Branches: refs/heads/OLINGO-324 67c9541a5 -> a95a8d336
[OLINGO-324] modify json.js#jsonParser function Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/commit/a95a8d33 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/tree/a95a8d33 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/diff/a95a8d33 Branch: refs/heads/OLINGO-324 Commit: a95a8d336b6e58961447b29536cf8963f4418fd5 Parents: 67c9541 Author: Sven Kobler <[email protected]> Authored: Fri Jun 20 14:42:05 2014 +0200 Committer: Sven Kobler <[email protected]> Committed: Fri Jun 20 14:42:05 2014 +0200 ---------------------------------------------------------------------- datajs/demo/tester.html | 11 ++ datajs/src/lib/datajs/utils.js | 7 +- datajs/src/lib/odata.js | 2 + datajs/src/lib/odata/json-light.js | 175 +++++++++++++++++++++++++------- datajs/src/lib/odata/json.js | 63 ++++++++++-- 5 files changed, 210 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/a95a8d33/datajs/demo/tester.html ---------------------------------------------------------------------- diff --git a/datajs/demo/tester.html b/datajs/demo/tester.html index 201920d..e1745d0 100644 --- a/datajs/demo/tester.html +++ b/datajs/demo/tester.html @@ -32,6 +32,7 @@ <button id="btnJSON_none">JSON odata.metadata=none</button><br/> <button id="btnJSON_minimal">JSON odata.metadata=minimal</button><br/> <button id="btnJSON_full">JSON odata.metadata=full</button><br/> + <button id="btnJSON_all">JSON odata.metadata=full with extend to all</button><br/> <button id="btnMetaData">MetaData</button><br/> <button id="btnJSONwithMetaData">JSON with MetaData</button><br/> <div id='resultsArea' data-type="json"> @@ -85,6 +86,16 @@ OData.read(requestUri, success, errorFunc); }); + $('#btnJSON_all').on("click", function(){ + var requestUri = { + requestUri : 'http://localhost:4002/tests/endpoints/FoodStoreDataServiceV4.svc/Foods', + headers : { Accept : 'application/json;odata.metadata=full' }, + extendMetadataToLevel : 'all' , + recognizeDates : true + }; + var context = { }; + OData.read(requestUri, success, errorFunc); + }); $('#btnMetaData').on("click", function(){ var oHeaders = { 'Accept': 'text/html,application/xhtml+xml,application/xml,application/json;odata.metadata=full', http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/a95a8d33/datajs/src/lib/datajs/utils.js ---------------------------------------------------------------------- diff --git a/datajs/src/lib/datajs/utils.js b/datajs/src/lib/datajs/utils.js index 51f73be..bd4f287 100644 --- a/datajs/src/lib/datajs/utils.js +++ b/datajs/src/lib/datajs/utils.js @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -519,6 +519,10 @@ var concatJsonValueArray = function (data, concatData) { return data; }; +var endsWith = function (input, search) { + return input.indexOf(search, input.length - search.length) !== -1; +}; + // DATAJS INTERNAL START exports.activeXObject = activeXObject; exports.assigned = assigned; @@ -544,6 +548,7 @@ exports.convertByteArrayToHexString = convertByteArrayToHexString; exports.getJsonValueArraryLength = getJsonValueArraryLength; exports.sliceJsonValueArray = sliceJsonValueArray; exports.concatJsonValueArray = concatJsonValueArray; +exports.endsWith = endsWith; // DATAJS INTERNAL END \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/a95a8d33/datajs/src/lib/odata.js ---------------------------------------------------------------------- diff --git a/datajs/src/lib/odata.js b/datajs/src/lib/odata.js index 47cc503..297a339 100644 --- a/datajs/src/lib/odata.js +++ b/datajs/src/lib/odata.js @@ -138,6 +138,7 @@ exports.request = function (request, success, error, handler, httpClient, metada // Augment the request with additional defaults. request.recognizeDates = utils.defined(request.recognizeDates, odataJson.jsonHandler.recognizeDates); + request.extendMetadataToLevel = utils.defined(request.extendMetadataToLevel, odataJson.jsonHandler.extendMetadataToLevel); request.callbackParameterName = utils.defined(request.callbackParameterName, odataNet.defaultHttpClient.callbackParameterName); request.formatQueryString = utils.defined(request.formatQueryString, odataNet.defaultHttpClient.formatQueryString); request.enableJsonpCallback = utils.defined(request.enableJsonpCallback, odataNet.defaultHttpClient.enableJsonpCallback); @@ -146,6 +147,7 @@ exports.request = function (request, success, error, handler, httpClient, metada var context = { metadata: metadata, recognizeDates: request.recognizeDates, + extendMetadataToLevel : request.extendMetadataToLevel, callbackParameterName: request.callbackParameterName, formatQueryString: request.formatQueryString, enableJsonpCallback: request.enableJsonpCallback, http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/a95a8d33/datajs/src/lib/odata/json-light.js ---------------------------------------------------------------------- diff --git a/datajs/src/lib/odata/json-light.js b/datajs/src/lib/odata/json-light.js index 9c4c079..17c2cba 100644 --- a/datajs/src/lib/odata/json-light.js +++ b/datajs/src/lib/odata/json-light.js @@ -69,12 +69,28 @@ var parseDuration = oDataUtils.parseDuration; // CONTENT START -var PAYLOADTYPE_OBJECT = "o"; var PAYLOADTYPE_FEED = "f"; -var PAYLOADTYPE_PRIMITIVE = "p"; +var PAYLOADTYPE_ENTRY = "e"; +var PAYLOADTYPE_PROPERTY = "p"; +var PAYLOADTYPE_ENTITY_REF_LINK = "erl"; +var PAYLOADTYPE_ENTITY_REF_LINKS = "erls"; +var PAYLOADTYPE_VALUE = "v"; +var PAYLOADTYPE_BINARY_VALUE = "bv"; var PAYLOADTYPE_COLLECTION = "c"; var PAYLOADTYPE_SVCDOC = "s"; -var PAYLOADTYPE_LINKS = "l"; +var PAYLOADTYPE_METADOC = "m"; +var PAYLOADTYPE_ERROR = "err"; +var PAYLOADTYPE_BATCH = "b"; +var PAYLOADTYPE_PARAMETER = "para"; +var PAYLOADTYPE_IND_PROPERTY = "ip"; +var PAYLOADTYPE_DELTA = "d"; +var PAYLOADTYPE_ASYNC = "a"; + + +var DELTATYPE_FEED = "f"; +var DELTATYPE_DELETED_ENTRY = "de"; +var DELTATYPE_LINK = "l"; +var DELTATYPE_DELETED_LINK = "dl"; var odataNs = "odata"; var odataAnnotationPrefix = odataNs + "."; @@ -1036,57 +1052,93 @@ var jsonLightMakePayloadInfo = function (kind, type) { return { kind: kind, type: type || null }; }; -var jsonLightPayloadInfo = function (data, model, inferFeedAsComplexType) { - /// <summary>Infers the information describing the JSON light payload from its metadata annotation, structure, and data model.</summary> - /// <param name="data" type="Object">Json light response payload object.</param> - /// <param name="model" type="Object">Object describing an OData conceptual schema.</param> - /// <param name="inferFeedAsComplexType" type="Boolean">True if a JSON light payload that looks like a feed should be treated as a complex type property instead.</param> - /// <remarks> - /// If the arguments passed to the function don't convey enough information about the payload to determine without doubt that the payload is a feed then it - /// will try to use the payload object structure instead. If the payload looks like a feed (has value property that is an array or non-primitive values) then - /// the function will report its kind as PAYLOADTYPE_FEED unless the inferFeedAsComplexType flag is set to true. This flag comes from the user request - /// and allows the user to control how the library behaves with an ambigous JSON light payload. - /// </remarks> - /// <returns type="Object"> - /// Object with kind and type fields. Null if there is no metadata annotation or the payload info cannot be obtained.. - /// </returns> +/**/ +var parseContextUriFragment = function( fragment ) { + var ret = {}; + + ret.deltaKind = undefined; + if (utils.endsWith(fragment, '/$entity')) { + fragment = fragment.substring(fragment.lenght - 8); + } else if (utils.endsWith(fragment, '/$delta')) { + ret.deltaKind = DELTATYPE_FEED; + fragment = fragment.substring(fragment.lenght - 7); + } else if (utils.endsWith(fragment, '/$deletedEntity')) { + ret.deltaKind = DELTATYPE_DELETED_ENTRY; + fragment = fragment.substring(fragment.lenght - 15); + } else if (utils.endsWith(fragment, '/$link')) { + ret.deltaKind = DELTATYPE_LINK; + fragment = fragment.substring(fragment.lenght - 6); + } else if (utils.endsWith(fragment, '/$deletedLink')) { + ret.deltaKind = DELTATYPE_DELETED_LINK; + fragment = fragment.substring(fragment.lenght - 13); + } + + if (utils.endsWith(fragment,")")) { + //remove the query function, cut fragment to matching '(' + var index = fragment.lenght - 2 ; + for ( var rCount = 1; rcount > 0 && index > 0; --index) { + if ( fragment.charAt(index)=='(') { + rCount ++; + } else if ( fragment.charAt(index)==')') { + rCount --; + } + } - var metadataUri = data[contextUrlAnnotation]; - if (!metadataUri || typeof metadataUri !== "string") { - return null; - } + if (index == 0) { + //TODO throw error + } - var fragmentStart = metadataUri.lastIndexOf("#"); - if (fragmentStart === -1) { - return jsonLightMakePayloadInfo(PAYLOADTYPE_SVCDOC); - } + var previous = fragment.substring(0, index + 1); - var elementStart = metadataUri.indexOf("@Element", fragmentStart); - var fragmentEnd = elementStart - 1; - if (fragmentEnd < 0) { - fragmentEnd = metadataUri.indexOf("?", fragmentStart); - if (fragmentEnd === -1) { - fragmentEnd = metadataUri.length; + if (previous !== 'Collection') { // Don't treat Collection(Edm.Type) as SelectExpand segment + var selectExpandStr = fragment.substring(index+2, fragment.lenght - 1); + var keyPattern = /^(?:-{0,1}\d+?|\w*'.+?'|[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}|.+?=.+?)$/; + var matches = keyPattern.exec(selectExpandStr); + if ( matches ) { + //TODO throw error + } + + ret.selectQueryOptionString = selectExpandStr; + fragment = previous; } - } - var fragment = metadataUri.substring(fragmentStart + 1, fragmentEnd); - if (fragment.indexOf("/$links/") > 0) { - return jsonLightMakePayloadInfo(PAYLOADTYPE_LINKS); } + ret.detectedPayloadKind = undefined; + if (fragment.indexOf('/') === -1 ) { + if (fragment.length === 0) { + // Capter 10.1 + ret.detectedPayloadKind = PAYLOADTYPE_SVCDOC; + } else if (fragment === 'Edm.Null') { + // Capter 10.15 + ret.detectedPayloadKind = PAYLOADTYPE_PROPERTY; + ret.isNullProperty = true; + } else if (fragment === 'Collection($ref)') { + // Capter 10.11 + ret.detectedPayloadKind = PAYLOADTYPE_ENTITY_REF_LINKS; + } else if (fragment === '$ref') { + // Capter 10.12 + ret.detectedPayloadKind = PAYLOADTYPE_ENTITY_REF_LINK; + } else { + //TODO check for navigation resource + } + } + + // split fragment at '/' + //TODO changes var fragmentParts = fragment.split("/"); if (fragmentParts.length >= 0) { var qualifiedName = fragmentParts[0]; var typeCast = fragmentParts[1]; if (jsonLightIsPrimitiveType(qualifiedName)) { - return jsonLightMakePayloadInfo(PAYLOADTYPE_PRIMITIVE, qualifiedName); + ret.detectedPayloadKind = PAYLOADTYPE_VALUE; + return ret; } if (isCollectionType(qualifiedName)) { - return jsonLightMakePayloadInfo(PAYLOADTYPE_COLLECTION, qualifiedName); + return ret; } var entityType = typeCast; @@ -1107,7 +1159,7 @@ var jsonLightPayloadInfo = function (data, model, inferFeedAsComplexType) { } var info; - if (elementStart > 0) { + if (d > 0) { info = jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, entityType); info.entitySet = entitySet; info.functionImport = functionImport; @@ -1135,7 +1187,52 @@ var jsonLightPayloadInfo = function (data, model, inferFeedAsComplexType) { return jsonLightMakePayloadInfo(PAYLOADTYPE_OBJECT, qualifiedName); } - return null; +}; + +var jsonLightPayloadInfo = function (data, model) { + /// <summary>Infers the information describing the JSON light payload from its metadata annotation, structure, and data model.</summary> + /// <param name="data" type="Object">Json light response payload object.</param> + /// <param name="model" type="Object">Object describing an OData conceptual schema.</param> + /// <remarks> + /// If the arguments passed to the function don't convey enough information about the payload to determine without doubt that the payload is a feed then it + /// will try to use the payload object structure instead. If the payload looks like a feed (has value property that is an array or non-primitive values) then + /// the function will report its kind as PAYLOADTYPE_FEED unless the inferFeedAsComplexType flag is set to true. This flag comes from the user request + /// and allows the user to control how the library behaves with an ambigous JSON light payload. + /// </remarks> + /// <returns type="Object"> + /// Object with kind and type fields. Null if there is no metadata annotation or the payload info cannot be obtained.. + /// </returns> + + var metadataUri = data[contextUrlAnnotation]; + if (!metadataUri || typeof metadataUri !== "string") { + return null; + } + + var fragmentStart = metadataUri.lastIndexOf("#"); + if (fragmentStart === -1) { + return jsonLightMakePayloadInfo(PAYLOADTYPE_SVCDOC); + } + + var d = metadataUri.indexOf("@Element", fragmentStart); + var fragmentEnd = elementStart - 1; + + if (fragmentEnd < 0) { + fragmentEnd = metadataUri.indexOf("?", fragmentStart); + if (fragmentEnd === -1) { + fragmentEnd = metadataUri.length; + } + } + + var fragment = metadataUri.substring(fragmentStart + 1, fragmentEnd); + if (fragment.indexOf("/$links/") > 0) { + return jsonLightMakePayloadInfo(PAYLOADTYPE_LINKS); + } + + var ret = parseContextUriFragment(fragment); + + return; + + }; var jsonLightReadPayload = function (data, model, recognizeDates, inferFeedAsComplexType, contentTypeOdata) { http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/a95a8d33/datajs/src/lib/odata/json.js ---------------------------------------------------------------------- diff --git a/datajs/src/lib/odata/json.js b/datajs/src/lib/odata/json.js index 28e71fd..c33104d 100644 --- a/datajs/src/lib/odata/json.js +++ b/datajs/src/lib/odata/json.js @@ -257,6 +257,7 @@ var jsonParser = function (handler, text, context) { } catch(err) { payloadFormat = 1; } + payloadFormat = (payloadFormat === undefined) ? 1 : payloadFormat; var demandedFormat = 1;//minmal try { @@ -264,6 +265,9 @@ var jsonParser = function (handler, text, context) { } catch(err) { demandedFormat = 1; } + demandedFormat = (demandedFormat === undefined) ? 1 : demandedFormat; + + //return jsonLightReadPayload(json, model, recognizeDates, inferJsonLightFeedAsObject, context.contentType.properties['odata.metadata']); if ( payloadFormat >= demandedFormat) { if (recognizeDates) { @@ -273,7 +277,8 @@ var jsonParser = function (handler, text, context) { } } else { if (payloadFormat === 2) { //full, no metadata in context required - //insert the missing type information for strings + //insert the missing type information for strings, bool, etc. + //guess type for nummber as defined in the odata-json-format-v4.0.doc specification return extendMetadataFromPayload(json,context,recognizeDates); } else if (payloadFormat === 1) { //minmal if (utils.isArray(context.metadata)) { @@ -288,18 +293,60 @@ var jsonParser = function (handler, text, context) { } } - //return jsonLightReadPayload(json, model, recognizeDates, inferJsonLightFeedAsObject, context.contentType.properties['odata.metadata']); + }; var convertPrimitivetypesGeneric = function(json,context) { - return json; -} -var extendMetadataFromPayload = function(json,context,recognizeDates) { - return json; -} + +}; + + +var addType = function(data, name, value ) { + var fullName = name+'@odata.type'; + + if ( data[fullName] === undefined) { + data[fullName] = value; + } +}; + +var extendMetadataFromPayload = function(data,context,recognizeDates) { + 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) { + extendMetadataFromPayload(data[key][i], context, recognizeDates); + } + } else if (utils.isObject(data[key])) { + if (data[key] !== null) { + extendMetadataFromPayload(data[key],context, recognizeDates); + } + } else { + var type = typeof data[key]; + if ( type === 'string' ) { + addType(data,key,'#String'); + } else if (type ==='boolean') { + addType(data,key,'#Bool'); + } else if (type ==='number') { + if ( data[key] % 1 === 0 ) { + addType(data,key,'#Integer'); + } else { + addType(data,key,'#Decimal'); + } + } + } + } + } + } + } + return data; +}; + var extendMetadataFromContext = function(json,context,recognizeDates) { return json; -} +}; var jsonToString = function (data) {
