Skip to content

Commit

Permalink
Pick up useful changes delivered under FAB-15190
Browse files Browse the repository at this point in the history
(manual cherry pick)
- Also switch to using pnpm

Signed-off-by: heatherlp <heatherpollard0@gmail.com>
  • Loading branch information
heatherlp authored and mbwhite committed Oct 31, 2019
1 parent 799bda1 commit 8ac11db
Show file tree
Hide file tree
Showing 20 changed files with 9,587 additions and 12,081 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ docs/**/_out

# Rush files
common/temp/**
.rush/temp/**
**/.rush/temp/**
**/*.build.error.log
**/*.build.log

Expand Down
50 changes: 39 additions & 11 deletions apis/fabric-contract-api/lib/annotations/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,52 @@ const logger = Logger.getLogger('./lib/annotations/object.js');
const utils = require('./utils');
require('reflect-metadata');

module.exports.Object = function Object () {
const getProto = function (prototype) {
return Object.getPrototypeOf(prototype);
};

module.exports.Object = function Object (opts) {
return (target) => {
logger.info('@Object args:', 'Target ->', target.name);
logger.info('@Object args: Target -> %s', target.constructor.name);

const objects = Reflect.getMetadata('fabric:objects', global) || {};

logger.debug('Existing fabric:objects', objects);
logger.debug('Existing fabric:objects %s', objects);

const properties = Reflect.getMetadata('fabric:object-properties', target.prototype) || {};

logger.debug('Existing fabric:object-properties for target', properties);

objects[target.name] = {
'$id': target.name,
type: 'object',
additionalProperties: false,
properties: properties
};
// check for the presence of a supertype
const supertype = getProto(target.prototype).constructor.name;

if (supertype === 'Object') {
objects[target.name] = {
'$id': target.name,
type: 'object',
cnstr: target,
properties: properties
};

// add in the discriminator property name if one has been supplied in the object annotations
if (opts && opts.discriminator) {
objects[target.name].discriminator = {propertyName: opts.discriminator};
}
} else {
objects[target.name] = {
'$id': target.name,
cnstr: target,
allOf: [
{
type: 'object',
properties: properties
},
{
'$ref': `${supertype}`
}
]
};
}

Reflect.defineMetadata('fabric:objects', objects, global);

Expand All @@ -44,9 +72,9 @@ module.exports.Object = function Object () {

module.exports.Property = function Property (name, type) {
return (target, propertyKey) => {
logger.info('@Property args:', `Property Key -> ${propertyKey}, Name -> ${name}, Type -> ${type},`, 'Target ->', target.constructor.name);
logger.debug('@Property args:', `Property Key -> ${propertyKey}, Name -> ${name}, Type -> ${type},`, 'Target ->', target.constructor.name);

const properties = Reflect.getMetadata('fabric:object-properties', target) || {};
const properties = Reflect.getOwnMetadata('fabric:object-properties', target) || {};

logger.debug('Existing fabric:object-properties for target', properties);

Expand Down
124 changes: 94 additions & 30 deletions apis/fabric-contract-api/lib/jsontransactionserializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

const Logger = require('./logger');
const logger = Logger.getLogger('./lib/jsontransactionserializer.js');
const {classToPlain, plainToClass} = require('class-transformer');

/**
* Uses the standard JSON serialization methods for converting to and from JSON strings
Expand All @@ -24,11 +25,11 @@ module.exports = class JSONSerializer {
* @param {Object} result to be converted
* @return {Buffer} container the encoded data
*/
toBuffer(result, schema = {}, loggerPrefix) {
toBuffer (result, schema = {}, loggerPrefix) {

// relay on the default algorithms, including for Buffers. Just retunring the buffer
// is not helpful on inflation; is this a buffer in and of itself, or a buffer to inflated to JSON?
if (!(typeof(result) === 'undefined' || result === null)) {
if (!(typeof (result) === 'undefined' || result === null)) {
// check that schema to see exactly how we should de-marshall this
if (schema.type && (schema.type === 'string' || schema.type === 'number')) {
// ok so this is a basic primitive type, and for strings and numbers the wireprotocol is different
Expand All @@ -38,9 +39,11 @@ module.exports = class JSONSerializer {
throw new Error(`Returned value is ${typeof result} does not match schema type of ${schema.type}`);
}
return Buffer.from(result.toString());
} else if (typeof result === 'number' || typeof result === 'string' || typeof result === 'boolean') {
return Buffer.from(result.toString());
} else {
logger.info(`${loggerPrefix} toBuffer has no schema/lacks sufficient schema to validate against`, schema);
const payload = JSON.stringify(result);
logger.debug(`${loggerPrefix} toBuffer has no schema/lacks sufficient schema to validate against`, schema);
const payload = JSON.stringify(classToPlain(result));
return Buffer.from(payload);
}
} else {
Expand All @@ -58,55 +61,116 @@ module.exports = class JSONSerializer {
* @return {Object} the resulting type
*
*/
fromBuffer(data, schema = {}, loggerPrefix) {
fromBuffer (data, fullschema, loggerPrefix) {

if (!data) {
logger.error(`${loggerPrefix} fromBuffer no data supplied`);
throw new Error('Buffer needs to be supplied');
}

if (!fullschema) {
throw new Error('Schema has not been specified');
}

const stringData = data.toString('utf8');

return this._fromString(stringData, fullschema, loggerPrefix);
}

_fromString (stringData, fullschema, loggerPrefix) {
let value;
let jsonForValidation;
let schema = fullschema.properties.prop;

// check that schema to see exactly how we should de-marshall this
if (schema.type && (schema.type === 'string' || schema.type === 'number')) {
// first confirm if this is a reference or not
if (schema.$ref) {
// set this as required
const type = schema.$ref.split(/\//).pop();
schema = fullschema.components.schemas[type];
schema.type = 'object';
logger.debug(`${loggerPrefix} tweaked schema to be ${schema}`);
}

// now can proceed to do the required conversion
if (schema.type) {
if (schema.type === 'string') {
logger.debug(`${loggerPrefix} fromBuffer handling data as string`);
// ok so this is a basic primitive type, and for strings and numbers the wireprotocol is different
value = data.toString();
value = stringData;
jsonForValidation = JSON.stringify(value);
} else {

return {value, jsonForValidation};
} else if (schema.type === 'number') {
logger.debug(`${loggerPrefix} fromBuffer handling data as number`);
value = Number(data.toString());
value = Number(stringData);
jsonForValidation = value;

if (isNaN(jsonForValidation)) {
throw new Error('fromBuffer could not convert data to number', data);
throw new Error('fromBuffer could not convert data to number', stringData);
}
}
} else {
return {value, jsonForValidation};
} else if (schema.type === 'boolean') {
logger.debug(`${loggerPrefix} fromBuffer handling data as boolean`);
const b = stringData.trim().toLowerCase();
switch (b) {
case 'true':
value = true;
break;
case 'false':
value = false;
break;
default:
throw new Error('fromBuffer could not convert data to boolean', stringData);

let json;
try {
json = JSON.parse(data.toString());
} catch (err) {
if (schema.type === 'boolean') {
throw new Error('fromBuffer could not convert data to boolean', data);
}
throw new Error('fromBuffer could not parse data as JSON to allow it to be converted to type: ' + JSON.stringify(schema.type), data, err);
jsonForValidation = value;
return {value, jsonForValidation};
} else if (schema.type === 'object') {
logger.debug(`${loggerPrefix} fromBuffer assuming data as object`);
// so this implies we have some json that should be formed up as an object
// need to get the constructor
const cnstr = fullschema.components.schemas[schema.$id].cnstr;
if (cnstr) {
logger.debug(`${loggerPrefix} fromBuffer handling data as object`);
jsonForValidation = JSON.parse(stringData);
value = plainToClass(cnstr, jsonForValidation);
return {value, jsonForValidation};
}
logger.debug(`${loggerPrefix} no known constructor`);
} else if (schema.type === 'array') {

jsonForValidation = JSON.parse(stringData);

value = jsonForValidation.map((v) => {
const _schema =
{
properties: {
prop: schema.items
},
components: fullschema.components
};

return (this._fromString(JSON.stringify(v), _schema, loggerPrefix)).value;
});
return {value, jsonForValidation};
}
if (json.type) {
}

try {
jsonForValidation = JSON.parse(stringData);
if (jsonForValidation.type && jsonForValidation.type === 'Buffer') {
logger.debug(`${loggerPrefix} fromBuffer handling data as buffer`);
if (json.type === 'Buffer') {
value = Buffer.from(json.data);
} else {
logger.error('fromBuffer could not convert data to useful type', data);
throw new Error(`${loggerPrefix} Type of ${json.type} is not understood, can't recreate data`);
}
value = Buffer.from(jsonForValidation.data);
} else {
logger.debug(`${loggerPrefix} fromBuffer handling data as json`);
value = json;
logger.debug(`${loggerPrefix} fromBuffer handling value and validation as the same`);
value = jsonForValidation;
}
// as JSON then this si the same
jsonForValidation = value;
} catch (err) {
logger.error('fromBuffer could not parse data as JSON to allow it to be converted to type: ' + JSON.stringify(schema.type), stringData, err);
logger.error('Converting data to string and JSON.stringify-ing');
value = stringData;
jsonForValidation = JSON.stringify(value);
}

return {value, jsonForValidation};
Expand Down
1 change: 1 addition & 0 deletions apis/fabric-contract-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
},
"dependencies": {
"fabric-shim-api": "2.0.0-snapshot",
"class-transformer": "^0.2.2",
"fast-safe-stringify": "~2.0.7",
"get-params": "^0.1.2",
"reflect-metadata": "^0.1.12",
Expand Down
3 changes: 1 addition & 2 deletions apis/fabric-contract-api/schema/contract-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@
"type": "object",
"description": "A complex type used in a domain",
"required": [
"$id",
"properties"
"$id"
],
"properties": {
"$id": {
Expand Down
Loading

0 comments on commit 8ac11db

Please sign in to comment.