Add JSONStringPacker
Add a helper for encoding JavaScript values into JSON String format. The implementation is based on JSON String format and preserves JavaScript objects like Buffers and Dates, as opposed to encoding format.
This commit is contained in:
parent
b698b82ce7
commit
d45aaec5ef
|
@ -0,0 +1,94 @@
|
|||
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
||||
// Node module: loopback-connector
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
'use strict';
|
||||
|
||||
var createPromiseCallback = require('./utils').createPromiseCallback;
|
||||
|
||||
module.exports = JSONStringPacker;
|
||||
|
||||
var ISO_DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/;
|
||||
|
||||
/**
|
||||
* Create a new Packer instance that can be used to convert between JavaScript
|
||||
* objects and a JsonString representation in a String.
|
||||
*
|
||||
* @param {String} encoding Buffer encoding refer to https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings
|
||||
*/
|
||||
function JSONStringPacker(encoding) {
|
||||
this.encoding = encoding || 'base64';
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the provided value to a `JsonString`.
|
||||
*
|
||||
* @param {*} value Any value (string, number, object)
|
||||
* @callback {Function} cb The callback to receive the parsed result.
|
||||
* @param {Error} err
|
||||
* @param {Buffer} data The encoded value
|
||||
* @promise
|
||||
*/
|
||||
JSONStringPacker.prototype.encode = function(value, cb) {
|
||||
var encoding = this.encoding;
|
||||
|
||||
cb = cb || createPromiseCallback();
|
||||
try {
|
||||
var data = JSON.stringify(value, function(key, value) {
|
||||
if (Buffer.isBuffer(this[key])) {
|
||||
return {
|
||||
type: 'Buffer',
|
||||
data: this[key].toString(encoding),
|
||||
};
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
setImmediate(function() {
|
||||
cb(null, data);
|
||||
});
|
||||
} catch (err) {
|
||||
setImmediate(function() {
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode the JsonString value back to a JavaScript value.
|
||||
* @param {String} jsonString The JsonString input.
|
||||
* @callback {Function} cb The callback to receive the composed value.
|
||||
* @param {Error} err
|
||||
* @param {*} value Decoded value.
|
||||
* @promise
|
||||
*/
|
||||
JSONStringPacker.prototype.decode = function(jsonString, cb) {
|
||||
var encoding = this.encoding;
|
||||
|
||||
cb = cb || createPromiseCallback();
|
||||
try {
|
||||
var value = JSON.parse(jsonString, function(k, v) {
|
||||
if (v && v.type && v.type === 'Buffer') {
|
||||
return new Buffer(v.data, encoding);
|
||||
}
|
||||
|
||||
if (ISO_DATE_REGEXP.exec(v)) {
|
||||
return new Date(v);
|
||||
}
|
||||
|
||||
return v;
|
||||
});
|
||||
|
||||
setImmediate(function() {
|
||||
cb(null, value);
|
||||
});
|
||||
} catch (err) {
|
||||
setImmediate(function() {
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
return cb.promise;
|
||||
};
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright IBM Corp. 2016. All Rights Reserved.
|
||||
// Node module: loopback-connector
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
'use strict';
|
||||
|
||||
var JSONStringPacker = require('../lib/json-string-packer');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
describe('JSONStringPacker', function() {
|
||||
var packer;
|
||||
|
||||
beforeEach(function createPacker() {
|
||||
packer = new JSONStringPacker();
|
||||
});
|
||||
|
||||
describe('encode()', function() {
|
||||
it('supports invocation with a callback', function(done) {
|
||||
packer.encode('a-value', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decode()', function() {
|
||||
it('supports invocation with a callback', function(done) {
|
||||
packer.encode('a-value', function(err, jsonString) {
|
||||
if (err) return done(err);
|
||||
packer.decode(jsonString, function(err, result) {
|
||||
if (err) return done(err);
|
||||
expect(result).to.eql('a-value');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('roundtrip', function() {
|
||||
var TEST_CASES = {
|
||||
String: 'a-value',
|
||||
Object: { a: 1, b: 2 },
|
||||
Buffer: new Buffer([1, 2, 3]),
|
||||
Date: new Date('2016-08-03T11:53:03.470Z'),
|
||||
Integer: 12345,
|
||||
Float: 12.345,
|
||||
Boolean: false,
|
||||
};
|
||||
|
||||
Object.keys(TEST_CASES).forEach(function(tc) {
|
||||
it('works for ' + tc + ' values', function() {
|
||||
var value = TEST_CASES[tc];
|
||||
return encodeAndDecode(value)
|
||||
.then(function(result) {
|
||||
expect(result).to.eql(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('works for nested properties', function() {
|
||||
return encodeAndDecode(TEST_CASES)
|
||||
.then(function(result) {
|
||||
expect(result).to.eql(TEST_CASES);
|
||||
});
|
||||
});
|
||||
|
||||
function encodeAndDecode(value) {
|
||||
return packer.encode(value)
|
||||
.then(function(binary) {
|
||||
return packer.decode(binary);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue