Skip to content

Commit

Permalink
Encode special symbols in the filter query parameter. Fixes #22
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandrRogov committed Mar 11, 2018
1 parent 5560906 commit c3e01a7
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 64 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impersonate | String | All | A String representing the GUID value for the Dynami
includeAnnotations | String | `retrieveRequest`, `retrieveMultipleRequest`, `retrieveAllRequest`, `createRequest`, `updateRequest`, `upsertRequest` | Sets Prefer header with value "odata.include-annotations=" and the specified annotation. Annotations provide additional information about lookups, options sets and other complex attribute types.
key | String | `retrieveRequest`, `createRequest`, `updateRequest`, `upsertRequest`, `deleteRequest` | `v.1.3.4+` A String representing collection record's Primary Key (GUID) or Alternate Key(s).
maxPageSize | Number | `retrieveMultipleRequest`, `retrieveAllRequest` | Sets the odata.maxpagesize preference value to request the number of entities returned in the response.
mergeLabels | Boolean | `updateRequest` | `v.1.4.2+` **Metadata Update only!** Sets `MSCRM.MergeLabels` header that controls whether to overwrite the existing labels or merge your new label with any existing language labels. [More info](https://msdn.microsoft.com/en-us/library/mt593078.aspx#Update%20entities)
mergeLabels | Boolean | `updateRequest` | `v.1.4.2+` **Metadata Update only!** Sets `MSCRM.MergeLabels` header that controls whether to overwrite the existing labels or merge your new label with any existing language labels. Default value is `false`. [More info](https://msdn.microsoft.com/en-us/library/mt593078.aspx#bkmk_updateEntities)
navigationProperty | String | `retrieveRequest` | A String representing the name of a single-valued navigation property. Useful when needed to retrieve information about a related record in a single request.
noCache | Boolean | All | `v.1.4.0+` If set to `true`, DynamicsWebApi adds a request header `Cache-Control: no-cache`. Default value is `false`.
orderBy | Array | `retrieveMultipleRequest`, `retrieveAllRequest` | An Array (of Strings) representing the order in which items are returned using the $orderby system query option. Use the asc or desc suffix to specify ascending or descending order respectively. The default is ascending if the suffix isn't applied.
Expand Down
98 changes: 71 additions & 27 deletions dist/dynamics-web-api-callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,24 @@ var buildPreferHeader = __webpack_require__(12);
* @property {boolean} async
*/

/**
* @param {Array} array
* @param {boolean} [performJoin]
* @param {boolean} [joinSymbol]
*/
function encodeURIComponentArray(array, performJoin, joinSymbol) {
performJoin = performJoin == null ? true : performJoin;
joinSymbol = joinSymbol || ',';

for (var i = 0; i < array.length; i++) {
array[i] = encodeURIComponent(array[i]);
}

return performJoin
? array.join(joinSymbol)
: array;
}

/**
* Converts optional parameters of the request to URL. If expand parameter exists this function is called recursively.
*
Expand Down Expand Up @@ -417,7 +435,7 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {
ErrorHelper.stringParameterCheck(request.filter, 'DynamicsWebApi.' + functionName, "request.filter");
var removeBracketsFromGuidReg = /[^"']{([\w\d]{8}[-]?(?:[\w\d]{4}[-]?){3}[\w\d]{12})}(?:[^"']|$)/g;
var filterResult = request.filter.replace(removeBracketsFromGuidReg, ' $1 ').trim();
requestArray.push("$filter=" + filterResult);
requestArray.push("$filter=" + encodeURIComponent(filterResult));
}

if (request.savedQuery) {
Expand Down Expand Up @@ -480,8 +498,6 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {

if (request.entity) {
ErrorHelper.parameterCheck(request.entity, 'DynamicsWebApi.' + functionName, 'request.entity');


}

if (request.data) {
Expand All @@ -493,7 +509,7 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {
headers['Cache-Control'] = 'no-cache';
}

if (request.mergeLabels){
if (request.mergeLabels) {
ErrorHelper.boolParameterCheck(request.mergeLabels, 'DynamicsWebApi.' + functionName, 'request.mergeLabels');
headers['MSCRM.MergeLabels'] = 'true';
}
Expand Down Expand Up @@ -571,7 +587,7 @@ function convertRequest(request, functionName, config) {
}
else
if (result.query) {
result.url += "?" + encodeURI(result.query);
result.url += "?" + result.query;
}
}
else {
Expand Down Expand Up @@ -2164,30 +2180,18 @@ function parseBatchResponse(response) {
return result;
}

function populateFormattedValues(object) {
var keys = Object.keys(object);
//object._dwa_extendedProperties = [];

for (var i = 0; i < keys.length; i++) {
if (object[keys[i]] != null && object[keys[i]].constructor === Array) {
for (var j = 0; j < object[keys[i]].length; j++) {
object[keys[i]][j] = populateFormattedValues(object[keys[i]][j]);
}
}

if (keys[i].indexOf('@') == -1)
continue;

var format = keys[i].split('@');
var newKey = null;
function getFormattedKeyValue(keyName, value) {
var newKey = null;
if (keyName.indexOf('@') !== -1) {
var format = keyName.split('@');
switch (format[1]) {
case 'odata.context':
newKey = 'oDataContext';
break;
case 'odata.count':
newKey = 'oDataCount';
object[keys[i]] = object[keys[i]] != null
? parseInt(object[keys[i]])
value = value != null
? parseInt(value)
: 0;
break;
case 'odata.nextLink':
Expand All @@ -2203,10 +2207,50 @@ function populateFormattedValues(object) {
newKey = format[0] + '_LogicalName';
break;
}
}

return [newKey, value];
}

function parseData(object) {
var keys = Object.keys(object);

for (var i = 0; i < keys.length; i++) {
var currentKey = keys[i];

if (object[currentKey] != null && object[currentKey].constructor === Array) {
for (var j = 0; j < object[currentKey].length; j++) {
object[currentKey][j] = parseData(object[currentKey][j]);
}
}

if (newKey) {
object[newKey] = object[keys[i]];
//object._dwa_extendedProperties.push(newKey);
//parse formatted values
var formattedKeyValue = getFormattedKeyValue(currentKey, object[currentKey]);
if (formattedKeyValue[0]) {
object[formattedKeyValue[0]] = formattedKeyValue[1];
}

//parse aliased values
if (currentKey.indexOf('_x002e_') !== -1) {
var aliasKeys = currentKey.split('_x002e_');

if (!object.hasOwnProperty(aliasKeys[0])) {
object[aliasKeys[0]] = { _dwaType: 'alias' };
}
//throw an error if there is already a property which is not an 'alias'
else if (
typeof (object[aliasKeys[0]]) !== 'object' ||
typeof (object[aliasKeys[0]]) === 'object' && !object[aliasKeys[0]].hasOwnProperty('_dwaType')) {
throw new Error('The alias name of the linked entity must be unique!');
}

object[aliasKeys[0]][aliasKeys[1]] = object[currentKey];

//aliases also contain formatted values
formattedKeyValue = getFormattedKeyValue(aliasKeys[1], object[currentKey]);
if (formattedKeyValue[0]) {
object[aliasKeys[0]][formattedKeyValue[0]] = formattedKeyValue[1];
}
}
}

Expand All @@ -2224,7 +2268,7 @@ module.exports = function parseResponse(response) {
? responseData = parseBatchResponse(response)[0]
: responseData = JSON.parse(response, dateReviver);

responseData = populateFormattedValues(responseData);
responseData = parseData(responseData);
}

return responseData;
Expand Down
2 changes: 1 addition & 1 deletion dist/dynamics-web-api-callbacks.min.js

Large diffs are not rendered by default.

120 changes: 93 additions & 27 deletions dist/dynamics-web-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,28 @@ function DynamicsWebApi(config) {
return this.retrieveRequest(request);
};

//this.retrieveAttributes = function (entityDefinitionId, attributeType, select, filter) {

// var navigationProperty = 'Attributes';

// if (attributeType) {
// ErrorHelper.stringParameterCheck(attributeType, "DynamicsWebApi.retrieveAttributes", "attributeType");
// navigationProperty += '/' + attributeType;
// }

// var request = {
// collection: 'EntityDefinitions',
// key: entityDefinitionId,
// navigationProperty: 'Attributes',
// select: select,
// filter: filter
// };

// return this.retrieveRequest(request);
//};

//this.retrieveAttribute = function(entityDefinitionId, attributeId, attributeType, select, expand

/**
* Sends an asynchronous request to update a record.
*
Expand Down Expand Up @@ -1792,30 +1814,18 @@ function parseBatchResponse(response) {
return result;
}

function populateFormattedValues(object) {
var keys = Object.keys(object);
//object._dwa_extendedProperties = [];

for (var i = 0; i < keys.length; i++) {
if (object[keys[i]] != null && object[keys[i]].constructor === Array) {
for (var j = 0; j < object[keys[i]].length; j++) {
object[keys[i]][j] = populateFormattedValues(object[keys[i]][j]);
}
}

if (keys[i].indexOf('@') == -1)
continue;

var format = keys[i].split('@');
var newKey = null;
function getFormattedKeyValue(keyName, value) {
var newKey = null;
if (keyName.indexOf('@') !== -1) {
var format = keyName.split('@');
switch (format[1]) {
case 'odata.context':
newKey = 'oDataContext';
break;
case 'odata.count':
newKey = 'oDataCount';
object[keys[i]] = object[keys[i]] != null
? parseInt(object[keys[i]])
value = value != null
? parseInt(value)
: 0;
break;
case 'odata.nextLink':
Expand All @@ -1831,10 +1841,50 @@ function populateFormattedValues(object) {
newKey = format[0] + '_LogicalName';
break;
}
}

return [newKey, value];
}

function parseData(object) {
var keys = Object.keys(object);

for (var i = 0; i < keys.length; i++) {
var currentKey = keys[i];

if (object[currentKey] != null && object[currentKey].constructor === Array) {
for (var j = 0; j < object[currentKey].length; j++) {
object[currentKey][j] = parseData(object[currentKey][j]);
}
}

//parse formatted values
var formattedKeyValue = getFormattedKeyValue(currentKey, object[currentKey]);
if (formattedKeyValue[0]) {
object[formattedKeyValue[0]] = formattedKeyValue[1];
}

//parse aliased values
if (currentKey.indexOf('_x002e_') !== -1) {
var aliasKeys = currentKey.split('_x002e_');

if (!object.hasOwnProperty(aliasKeys[0])) {
object[aliasKeys[0]] = { _dwaType: 'alias' };
}
//throw an error if there is already a property which is not an 'alias'
else if (
typeof (object[aliasKeys[0]]) !== 'object' ||
typeof (object[aliasKeys[0]]) === 'object' && !object[aliasKeys[0]].hasOwnProperty('_dwaType')) {
throw new Error('The alias name of the linked entity must be unique!');
}

object[aliasKeys[0]][aliasKeys[1]] = object[currentKey];

if (newKey) {
object[newKey] = object[keys[i]];
//object._dwa_extendedProperties.push(newKey);
//aliases also contain formatted values
formattedKeyValue = getFormattedKeyValue(aliasKeys[1], object[currentKey]);
if (formattedKeyValue[0]) {
object[aliasKeys[0]][formattedKeyValue[0]] = formattedKeyValue[1];
}
}
}

Expand All @@ -1852,7 +1902,7 @@ module.exports = function parseResponse(response) {
? responseData = parseBatchResponse(response)[0]
: responseData = JSON.parse(response, dateReviver);

responseData = populateFormattedValues(responseData);
responseData = parseData(responseData);
}

return responseData;
Expand Down Expand Up @@ -1987,6 +2037,24 @@ var buildPreferHeader = __webpack_require__(12);
* @property {boolean} async
*/

/**
* @param {Array} array
* @param {boolean} [performJoin]
* @param {boolean} [joinSymbol]
*/
function encodeURIComponentArray(array, performJoin, joinSymbol) {
performJoin = performJoin == null ? true : performJoin;
joinSymbol = joinSymbol || ',';

for (var i = 0; i < array.length; i++) {
array[i] = encodeURIComponent(array[i]);
}

return performJoin
? array.join(joinSymbol)
: array;
}

/**
* Converts optional parameters of the request to URL. If expand parameter exists this function is called recursively.
*
Expand Down Expand Up @@ -2035,7 +2103,7 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {
ErrorHelper.stringParameterCheck(request.filter, 'DynamicsWebApi.' + functionName, "request.filter");
var removeBracketsFromGuidReg = /[^"']{([\w\d]{8}[-]?(?:[\w\d]{4}[-]?){3}[\w\d]{12})}(?:[^"']|$)/g;
var filterResult = request.filter.replace(removeBracketsFromGuidReg, ' $1 ').trim();
requestArray.push("$filter=" + filterResult);
requestArray.push("$filter=" + encodeURIComponent(filterResult));
}

if (request.savedQuery) {
Expand Down Expand Up @@ -2098,8 +2166,6 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {

if (request.entity) {
ErrorHelper.parameterCheck(request.entity, 'DynamicsWebApi.' + functionName, 'request.entity');


}

if (request.data) {
Expand All @@ -2111,7 +2177,7 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {
headers['Cache-Control'] = 'no-cache';
}

if (request.mergeLabels){
if (request.mergeLabels) {
ErrorHelper.boolParameterCheck(request.mergeLabels, 'DynamicsWebApi.' + functionName, 'request.mergeLabels');
headers['MSCRM.MergeLabels'] = 'true';
}
Expand Down Expand Up @@ -2189,7 +2255,7 @@ function convertRequest(request, functionName, config) {
}
else
if (result.query) {
result.url += "?" + encodeURI(result.query);
result.url += "?" + result.query;
}
}
else {
Expand Down
2 changes: 1 addition & 1 deletion dist/dynamics-web-api.min.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion lib/dynamics-web-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ var dwaRequest = function () {
impersonate: "",
navigationProperty: "",
savedQuery: "",
userQuery: ""
userQuery: "",
mergeLabels: false
}
};
/* develblock:end */
Expand Down
6 changes: 3 additions & 3 deletions lib/utilities/RequestConverter.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {
ErrorHelper.stringParameterCheck(request.filter, 'DynamicsWebApi.' + functionName, "request.filter");
var removeBracketsFromGuidReg = /[^"']{([\w\d]{8}[-]?(?:[\w\d]{4}[-]?){3}[\w\d]{12})}(?:[^"']|$)/g;
var filterResult = request.filter.replace(removeBracketsFromGuidReg, ' $1 ').trim();
requestArray.push("$filter=" + filterResult);
requestArray.push("$filter=" + encodeURIComponent(filterResult));
}

if (request.savedQuery) {
Expand Down Expand Up @@ -138,7 +138,7 @@ function convertRequestOptions(request, functionName, url, joinSymbol, config) {
headers['Cache-Control'] = 'no-cache';
}

if (request.mergeLabels){
if (request.mergeLabels) {
ErrorHelper.boolParameterCheck(request.mergeLabels, 'DynamicsWebApi.' + functionName, 'request.mergeLabels');
headers['MSCRM.MergeLabels'] = 'true';
}
Expand Down Expand Up @@ -216,7 +216,7 @@ function convertRequest(request, functionName, config) {
}
else
if (result.query) {
result.url += "?" + encodeURI(result.query);
result.url += "?" + result.query;
}
}
else {
Expand Down
Loading

0 comments on commit c3e01a7

Please sign in to comment.