Fix the data type issue (https://github.com/Azure/azure-storage-node/issues/40)
This commit is contained in:
Родитель
4b8e2b933d
Коммит
d70a574f9d
|
@ -1,6 +1,12 @@
|
|||
Note: This is an Azure Storage only package. The all up Azure node sdk still has the old storage bits in there. In a future release, those storage bits will be removed and an npm dependency to this storage node sdk will
|
||||
be taken. This is a GA preview release and the changes described below indicate the changes from the Azure node SDK 0.9.8 available here - https://github.com/Azure/azure-sdk-for-node.
|
||||
|
||||
2016.05 Version 1.0.0
|
||||
|
||||
TABLE
|
||||
* Fixed the issue that loses the data type for Edm.Double value like: 1.0.
|
||||
* Fixed the issue that loses the data precision for Edm.Int64 value when it is outisde of the range (2^53 - 1) to -(2^53 - 1).
|
||||
|
||||
2016.03 Version 0.10.0
|
||||
|
||||
ALL
|
||||
|
|
|
@ -25,6 +25,7 @@ var guid = require('node-uuid');
|
|||
var os = require('os');
|
||||
var crypto = require('crypto');
|
||||
var extend = require('extend');
|
||||
var Parser = require('json-edm-parser');
|
||||
|
||||
var azureutil = require('../util/util');
|
||||
var validate = require('../util/validate');
|
||||
|
@ -36,6 +37,7 @@ var StorageServiceSettings = require('./storageservicesettings');
|
|||
var Constants = require('../util/constants');
|
||||
var StorageUtilities = require('../util/storageutilities');
|
||||
var ServicePropertiesResult = require('../models/servicepropertiesresult');
|
||||
var TableUtilities = require('../../services/table/tableutilities');
|
||||
|
||||
var SharedKey = require('../signing/sharedkey');
|
||||
var SharedAccessSignature = require('../signing/sharedaccesssignature');
|
||||
|
@ -289,7 +291,7 @@ StorageServiceClient.prototype._performRequest = function (webResource, body, op
|
|||
if (error) {
|
||||
responseObject = { error: error, response: null };
|
||||
} else {
|
||||
responseObject = self._processResponse(webResource, response);
|
||||
responseObject = self._processResponse(webResource, response, options);
|
||||
responseObject.contentMD5 = response.contentMD5;
|
||||
responseObject.length = response.length;
|
||||
}
|
||||
|
@ -576,11 +578,13 @@ StorageServiceClient.prototype._buildRequestOptions = function (webResource, bod
|
|||
* Process the response.
|
||||
* @ignore
|
||||
*
|
||||
* @param {WebResource} webResource The web resource that made the request.
|
||||
* @param {Response} response The response object.
|
||||
* @param {WebResource} webResource The web resource that made the request.
|
||||
* @param {Response} response The response object.
|
||||
* @param {Options} options The response parsing options.
|
||||
* @param {String} options.payloadFormat The payload format.
|
||||
* @return The normalized responseObject.
|
||||
*/
|
||||
StorageServiceClient.prototype._processResponse = function (webResource, response) {
|
||||
StorageServiceClient.prototype._processResponse = function (webResource, response, options) {
|
||||
var self = this;
|
||||
|
||||
var validResponse = WebResource.validResponse(response.statusCode);
|
||||
|
@ -591,7 +595,7 @@ StorageServiceClient.prototype._processResponse = function (webResource, respons
|
|||
responseObject = { error: null, response: rsp };
|
||||
} else {
|
||||
// attempt to parse the response body, errors will be returned in rsp.error without modifying the body
|
||||
rsp = StorageServiceClient._parseResponse(rsp, self.xml2jsSettings);
|
||||
rsp = StorageServiceClient._parseResponse(rsp, self.xml2jsSettings, options);
|
||||
|
||||
if (validResponse && !rsp.error) {
|
||||
responseObject = { error: null, response: rsp };
|
||||
|
@ -712,10 +716,13 @@ StorageServiceClient._buildResponse = function (isSuccessful, body, headers, sta
|
|||
* This is done using the xml2js library.
|
||||
* @ignore
|
||||
*
|
||||
* @param {object} response The response object with a property "body" with a XML or JSON string content.
|
||||
* @param {object} response The response object with a property "body" with a XML or JSON string content.
|
||||
* @param {object} xml2jsSettings The XML to json settings.
|
||||
* @param {Options} options The response parsing options.
|
||||
* @param {String} options.payloadFormat The payload format.
|
||||
* @return {object} The same response object with the body part as a JS object instead of a XML or JSON string.
|
||||
*/
|
||||
StorageServiceClient._parseResponse = function (response, xml2jsSettings) {
|
||||
StorageServiceClient._parseResponse = function (response, xml2jsSettings, options) {
|
||||
function parseXml(body) {
|
||||
var parsed;
|
||||
var parser = new xml2js.Parser(xml2jsSettings);
|
||||
|
@ -738,7 +745,15 @@ StorageServiceClient._parseResponse = function (response, xml2jsSettings) {
|
|||
|
||||
try {
|
||||
if (contentType.indexOf('application/json') !== -1) {
|
||||
response.body = JSON.parse(response.body);
|
||||
if (options && options.payloadFormat && options.payloadFormat !== TableUtilities.PayloadFormat.NO_METADATA) {
|
||||
var parser = new Parser();
|
||||
parser.onValue = function (value) {
|
||||
response.body = value;
|
||||
};
|
||||
parser.write(response.body);
|
||||
} else {
|
||||
response.body = JSON.parse(response.body);
|
||||
}
|
||||
} else if (contentType.indexOf('application/xml') !== -1 || contentType.indexOf('application/atom+xml') !== -1) {
|
||||
response.body = parseXml(response.body);
|
||||
} else {
|
||||
|
|
|
@ -119,12 +119,8 @@ exports.serializeValue = function (type, value) {
|
|||
}
|
||||
return value;
|
||||
case EdmType.INT64:
|
||||
return value.toString();
|
||||
case EdmType.DOUBLE:
|
||||
if(azureutil.objectIsInt(value)) {
|
||||
return value + '.0';
|
||||
}
|
||||
return value;
|
||||
return value.toString();
|
||||
case EdmType.INT32:
|
||||
if (value === Number.POSITIVE_INFINITY) {
|
||||
return 'Infinity';
|
||||
|
@ -153,9 +149,9 @@ exports.isTypeRequired = function(type, value) {
|
|||
case EdmType.INT64:
|
||||
case EdmType.DATETIME:
|
||||
case EdmType.GUID:
|
||||
case EdmType.DOUBLE:
|
||||
return true;
|
||||
case EdmType.INT32:
|
||||
case EdmType.DOUBLE:
|
||||
if (value === Number.POSITIVE_INFINITY || value === Number.NEGATIVE_INFINITY || (Number.isNaN(value))) {
|
||||
return true;
|
||||
}
|
||||
|
@ -182,7 +178,7 @@ exports.serializeQueryValue = function (value, type) {
|
|||
case EdmType.BOOLEAN:
|
||||
return value ? 'true' : 'false';
|
||||
case EdmType.DOUBLE:
|
||||
return azureutil.objectIsInt(value) ? '\'' + value + '.0' + '\'': value.toString();
|
||||
return value.toString();
|
||||
case EdmType.INT64:
|
||||
return value.toString() + 'L';
|
||||
case EdmType.DATETIME:
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"dependencies": {
|
||||
"extend": "~1.2.1",
|
||||
"browserify-mime": "~1.2.9",
|
||||
"json-edm-parser": "0.1.1",
|
||||
"node-uuid": "~1.4.0",
|
||||
"readable-stream": "~2.0.0",
|
||||
"request": "~2.69.0",
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -198,6 +198,20 @@ describe('tableservice-payload-tests', function () {
|
|||
fnHelper(specialNumbersTest, options, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Data/Type Integrity', function () {
|
||||
it('FullMetadata', function (done) {
|
||||
var options = {};
|
||||
options.payloadFormat = TableUtilities.PayloadFormat.FULL_METADATA;
|
||||
fnHelper(dataTypeIntegrityTest, options, done);
|
||||
});
|
||||
|
||||
it('MinimalMetadata', function (done) {
|
||||
var options = {};
|
||||
options.payloadFormat = TableUtilities.PayloadFormat.MINIMAL_METADATA;
|
||||
fnHelper(dataTypeIntegrityTest, options, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EntityResolver', function () {
|
||||
it('FullMetadata', function (done) {
|
||||
|
@ -276,7 +290,11 @@ function compareProperties (propFromService, prop, expectTypeOnService) {
|
|||
// check type
|
||||
if (expectTypeOnService.val) {
|
||||
if (expectTypeOnService.stringOverride) {
|
||||
assert.strictEqual(propFromService['$'], 'Edm.String');
|
||||
if (prop['$'] === 'Edm.Double' && azureutil.objectIsInt(parseFloat(prop['_'])) ) {
|
||||
assert.strictEqual(propFromService['$'], prop['$']);
|
||||
} else {
|
||||
assert.strictEqual(propFromService['$'], 'Edm.String');
|
||||
}
|
||||
} else {
|
||||
assert.strictEqual(propFromService['$'], prop['$']);
|
||||
}
|
||||
|
@ -286,12 +304,18 @@ function compareProperties (propFromService, prop, expectTypeOnService) {
|
|||
|
||||
// check value, make sure typeof is equal as Number.NaN should not equal 'Nan'
|
||||
if (propFromService.hasOwnProperty('$') && !expectTypeOnService.stringOverride) {
|
||||
assert.strictEqual(typeof propFromService['_'], typeof prop['_']);
|
||||
if (prop['$'] === 'Edm.Double' && azureutil.objectIsInt(parseFloat(prop['_'])) ) {
|
||||
assert.strictEqual(typeof propFromService['_'], "number");
|
||||
} else {
|
||||
assert.strictEqual(typeof propFromService['_'], typeof prop['_']);
|
||||
}
|
||||
}
|
||||
if (prop['$'] === 'Edm.Binary' && (!propFromService.hasOwnProperty('$') || propFromService['$'] === 'Edm.String')) {
|
||||
assert.strictEqual(new Buffer(propFromService['_'], 'base64').toString(), prop['_'].toString());
|
||||
} else if (prop['$'] === 'Edm.DateTime' && (!propFromService.hasOwnProperty('$') || propFromService['$'] === 'Edm.String')){
|
||||
assert.strictEqual((new Date(propFromService['_'])).toString(), prop['_'].toString());
|
||||
} else if (prop['$'] === 'Edm.Double') {
|
||||
assert.strictEqual(propFromService['_'].toString(), parseFloat(prop['_']).toString());
|
||||
} else {
|
||||
assert.strictEqual(propFromService['_'].toString(), prop['_'].toString());
|
||||
}
|
||||
|
@ -310,8 +334,13 @@ var expectPropType = function (options, property) {
|
|||
}
|
||||
|
||||
if (property['$'] === 'Edm.Int32' || property['$'] === 'Edm.Double') {
|
||||
if ((Number.isNaN(property['_']) || property['_'] === Number.POSITIVE_INFINITY || property['_'] === Number.NEGATIVE_INFINITY) && (options.payloadFormat !== TableUtilities.PayloadFormat.NO_METADATA || options.autoResolveProperties)) {
|
||||
return {val: true, stringOverride: (options.autoResolveProperties && options.payloadFormat === TableUtilities.PayloadFormat.NO_METADATA)};
|
||||
if ((Number.isNaN(property['_'])
|
||||
|| property['_'] === Number.POSITIVE_INFINITY
|
||||
|| property['_'] === Number.NEGATIVE_INFINITY
|
||||
|| (property['$'] === 'Edm.Double' && azureutil.objectIsInt(parseFloat(property['_'])) ) )
|
||||
&& (options.payloadFormat !== TableUtilities.PayloadFormat.NO_METADATA || options.autoResolveProperties)) {
|
||||
var overrideDouble = (property['$'] === 'Edm.Double') && (parseFloat(property['_']).toString() !== property['_'].toString());
|
||||
return {val: true, stringOverride: overrideDouble || (options.autoResolveProperties && options.payloadFormat === TableUtilities.PayloadFormat.NO_METADATA)};
|
||||
} else {
|
||||
return {val: false};
|
||||
}
|
||||
|
@ -379,7 +408,7 @@ function selectBaseCaseTest (options, done) {
|
|||
tableService.retrieveEntity(tableName, entityToTest.PartitionKey['_'], entityToTest.RowKey['_'], options, function (error3, entity) {
|
||||
assert.equal(error3, null);
|
||||
assert.notEqual(entity, null);
|
||||
|
||||
|
||||
compareEntities(entity, entityToTest, options);
|
||||
|
||||
done();
|
||||
|
@ -448,6 +477,39 @@ function specialNumbersTest (options, done) {
|
|||
});
|
||||
}
|
||||
|
||||
function dataTypeIntegrityTest (options, done) {
|
||||
tableService.createTable(tableName, function (error1) {
|
||||
assert.equal(error1, null);
|
||||
|
||||
var entityToTest = {
|
||||
PartitionKey: eg.String('partition1'),
|
||||
RowKey: eg.String('row1'),
|
||||
RegularDouble: eg.Double(4.81516423423),
|
||||
NanDouble: eg.Double(Number.NaN),
|
||||
DoubleInInt: eg.Double(10.0),
|
||||
DoubleInIntString: eg.Double('10.0'),
|
||||
PositiveInfinityDouble: eg.Double(Number.POSITIVE_INFINITY),
|
||||
NegativeInfinityDouble: eg.Double(Number.NEGATIVE_INFINITY),
|
||||
MinDouble: eg.Double(Number.MIN_VALUE),
|
||||
MaxDouble: eg.Double(Number.MAX_VALUE),
|
||||
MaxInt64: eg.Int64('9223372036854775807')
|
||||
};
|
||||
|
||||
tableService.insertEntity(tableName, entityToTest, function (error2) {
|
||||
assert.equal(error2, null);
|
||||
|
||||
tableService.retrieveEntity(tableName, entityToTest.PartitionKey['_'], entityToTest.RowKey['_'], options, function (error3, entity) {
|
||||
assert.equal(error3, null);
|
||||
assert.notEqual(entity, null);
|
||||
|
||||
compareEntities(entity, entityToTest, options);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function entityResolverTest (options, done) {
|
||||
tableService.createTable(tableName, function (error1) {
|
||||
assert.equal(error1, null);
|
||||
|
|
Загрузка…
Ссылка в новой задаче