Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Commit f2adfab

Browse files
Dave Kelseynklincoln
Dave Kelsey
authored andcommitted
[Master] Move experimental features to 0.20 (#4593)
Signed-off-by: Dave Kelsey <d_kelsey@uk.ibm.com>
1 parent 9f836cb commit f2adfab

32 files changed

+1032
-112
lines changed

packages/composer-common/api.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,12 @@ class ModelManager {
258258
+ DecoratorFactory[] getDecoratorFactories()
259259
+ void addDecoratorFactory(DecoratorFactory)
260260
}
261+
class ReadOnlyDecorator extends Decorator {
262+
+ void constructor(Object) throws IllegalModelException
263+
}
264+
class ReadOnlyDecoratorFactory extends DecoratorFactory {
265+
+ Decorator newDecorator(Object)
266+
}
261267
class ReturnsDecorator extends Decorator {
262268
+ void constructor(Object) throws IllegalModelException
263269
+ string getType()
@@ -272,7 +278,7 @@ class ReturnsDecoratorFactory extends DecoratorFactory {
272278
class Serializer {
273279
+ void constructor(Factory,ModelManager)
274280
+ void setDefaultOptions(Object)
275-
+ Object toJSON(Resource,Object,boolean,boolean,boolean,boolean) throws Error
281+
+ Object toJSON(Resource,Object,boolean,boolean,boolean,boolean,boolean) throws Error
276282
+ Resource fromJSON(Object,Object,boolean,boolean)
277283
}
278284
class Wallet {

packages/composer-common/changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
# Note that the latest public API is documented using JSDocs and is available in api.txt.
2525
#
2626

27+
Version 0.19.20 {308d962120667e982b2600107d0b8b13} 2019-01-29
28+
- Modify readonly decorator to be parameterless
29+
30+
Version 0.19.20 {5ff216eab17b2d990c43636c51a585b5} 2018-12-18
31+
- Add readonly decorator factory
32+
2733
Version 0.19.11 {765772c9b73656c289a15398bccc76fd} 2018-06-29
2834
- Add decorator factories
2935
- Add returns decorator factory

packages/composer-common/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ module.exports.Query = require('./lib/query/query');
9292
module.exports.QueryAnalyzer = require('./lib/query/queryanalyzer.js');
9393
module.exports.QueryFile = require('./lib/query/queryfile');
9494
module.exports.QueryManager = require('./lib/querymanager');
95+
module.exports.ReadOnlyDecoratorFactory = require('./lib/readonlydecoratorfactory');
9596
module.exports.Relationship = require('./lib/model/relationship');
9697
module.exports.RelationshipDeclaration = require('./lib/introspect/relationshipdeclaration');
9798
module.exports.Resource = require('./lib/model/resource');

packages/composer-common/lib/businessnetworkdefinition.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const minimatch = require('minimatch');
2727
const ModelManager = require('./modelmanager');
2828
const QueryFile = require('./query/queryfile');
2929
const QueryManager = require('./querymanager');
30+
const ReadOnlyDecoratorFactory = require('./readonlydecoratorfactory');
3031
const ReturnsDecoratorFactory = require('./returnsdecoratorfactory');
3132
const ScriptManager = require('./scriptmanager');
3233
const semver = require('semver');
@@ -117,6 +118,7 @@ class BusinessNetworkDefinition {
117118

118119
this.modelManager = new ModelManager();
119120
this.modelManager.addDecoratorFactory(new CommitDecoratorFactory());
121+
this.modelManager.addDecoratorFactory(new ReadOnlyDecoratorFactory());
120122
this.modelManager.addDecoratorFactory(new ReturnsDecoratorFactory());
121123
this.factory = this.modelManager.getFactory();
122124
this.serializer = this.modelManager.getSerializer();

packages/composer-common/lib/introspect/property.js

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,25 +124,35 @@ class Property extends Decorated {
124124
* @return {string} the fully qualified type of this property
125125
*/
126126
getFullyQualifiedTypeName() {
127+
127128
if(this.isPrimitive()) {
128129
return this.type;
129130
}
130131

131-
const parent = this.getParent();
132-
if(!parent) {
133-
throw new Error('Property ' + this.name + ' does not have a parent.');
134-
}
135-
const modelFile = parent.getModelFile();
136-
if(!modelFile) {
137-
throw new Error('Parent of property ' + this.name + ' does not have a ModelFile!');
138-
}
132+
if (this.fullyQualifiedTypeName){
133+
return this.fullyQualifiedTypeName;
134+
} else {
135+
const parent = this.getParent();
136+
if(!parent) {
137+
throw new Error('Property ' + this.name + ' does not have a parent.');
138+
}
139+
const modelFile = parent.getModelFile();
140+
if(!modelFile) {
141+
throw new Error('Parent of property ' + this.name + ' does not have a ModelFile!');
142+
}
143+
144+
const result = modelFile.getFullyQualifiedTypeName(this.type);
145+
146+
if(!result) {
147+
throw new Error('Failed to find fully qualified type name for property ' + this.name + ' with type ' + this.type );
148+
}
149+
150+
this.fullyQualifiedTypeName = result;
151+
Object.defineProperty(this, 'fullyQualifiedTypeName', { enumerable: false });
139152

140-
const result = modelFile.getFullyQualifiedTypeName(this.type);
141-
if(!result) {
142-
throw new Error('Failed to find fully qualified type name for property ' + this.name + ' with type ' + this.type );
153+
return result;
143154
}
144155

145-
return result;
146156
}
147157

148158
/**
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
'use strict';
16+
17+
const Decorator = require('./introspect/decorator');
18+
const IllegalModelException = require('./introspect/illegalmodelexception');
19+
20+
/**
21+
* Specialised decorator implementation for the @readonly decorator.
22+
*/
23+
class ReadOnlyDecorator extends Decorator {
24+
25+
/**
26+
* Create a Decorator.
27+
* @param {ClassDeclaration | Property} parent - the owner of this property
28+
* @param {Object} ast - The AST created by the parser
29+
* @throws {IllegalModelException}
30+
*/
31+
constructor(parent, ast) {
32+
super(parent, ast);
33+
}
34+
35+
/**
36+
* Process the AST and build the model
37+
* @throws {IllegalModelException}
38+
* @private
39+
*/
40+
process() {
41+
super.process();
42+
const args = this.getArguments();
43+
if (args.length !== 0) {
44+
throw new IllegalModelException(`@readonly decorator expects 0 arguments, but ${args.length} arguments were specified.`, this.parent.getModelFile(), this.ast.location);
45+
}
46+
}
47+
48+
}
49+
50+
module.exports = ReadOnlyDecorator;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
'use strict';
16+
17+
const DecoratorFactory = require('./introspect/decoratorfactory');
18+
const ReadOnlyDecorator = require('./readonlydecorator');
19+
20+
/**
21+
* A decorator factory for the @readonly decorator.
22+
*/
23+
class ReadOnlyDecoratorFactory extends DecoratorFactory {
24+
25+
/**
26+
* Process the decorator, and return a specific implementation class for that
27+
* decorator, or return null if this decorator is not handled by this processor.
28+
* @abstract
29+
* @param {ClassDeclaration | Property} parent - the owner of this property
30+
* @param {Object} ast - The AST created by the parser
31+
* @return {Decorator} The decorator.
32+
*/
33+
newDecorator(parent, ast) {
34+
if (ast.name !== 'readonly') {
35+
return null;
36+
}
37+
return new ReadOnlyDecorator(parent, ast);
38+
}
39+
40+
}
41+
42+
module.exports = ReadOnlyDecoratorFactory;

packages/composer-common/lib/serializer.js

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ class Serializer {
6868
this.defaultOptions = Object.assign({}, baseDefaultOptions, newDefaultOptions);
6969
}
7070

71+
72+
/**
73+
* Generate validation parameters for a Resource
74+
* @private
75+
* @param {Resource} resource - The instance being worked
76+
* @returns {Object} parameters used for validation
77+
*/
78+
validationParameters(resource){
79+
const parameters = {};
80+
parameters.stack = new TypedStack(resource);
81+
parameters.modelManager = this.modelManager;
82+
parameters.seenResources = new Set();
83+
parameters.dedupeResources = new Set();
84+
return parameters;
85+
}
86+
7187
/**
7288
* <p>
7389
* Convert a {@link Resource} to a JavaScript object suitable for long-term
@@ -84,6 +100,9 @@ class Serializer {
84100
* @param {boolean} [options.deduplicateResources] - Generate $id for resources and
85101
* if a resources appears multiple times in the object graph only the first instance is
86102
* serialized in full, subsequent instances are replaced with a reference to the $id
103+
* @param {boolean} [options.useOriginal] - shortcut the generation of the JSON structure from
104+
* the resource and directly return the $original if present from the creation of the resource
105+
* through the fromJSON method
87106
* @return {Object} - The Javascript Object that represents the resource
88107
* @throws {Error} - throws an exception if resource is not an instance of
89108
* Resource or fails validation.
@@ -94,15 +113,18 @@ class Serializer {
94113
throw new Error(Globalize.formatMessage('serializer-tojson-notcobject'));
95114
}
96115

97-
const parameters = {};
98-
parameters.stack = new TypedStack(resource);
99-
parameters.modelManager = this.modelManager;
100-
parameters.seenResources = new Set();
101-
parameters.dedupeResources = new Set();
116+
// Assign options
117+
options = options ? Object.assign({}, this.defaultOptions, options) : this.defaultOptions;
118+
119+
// Enable shortcut retrieval of original JSON stored during serializer.fromJSON() method call
120+
if (resource.$original && options.useOriginal) {
121+
return resource.$original;
122+
}
123+
124+
const parameters = this.validationParameters(resource);
102125
const classDeclaration = this.modelManager.getType( resource.getFullyQualifiedType() );
103126

104-
// validate the resource against the model
105-
options = options ? Object.assign({}, this.defaultOptions, options) : this.defaultOptions;
127+
// conditionally validate the resource against the model
106128
if(options.validate) {
107129
const validator = new ResourceValidator(options);
108130
classDeclaration.accept(validator, parameters);
@@ -120,6 +142,7 @@ class Serializer {
120142
// this performs the conversion of the resouce into a standard JSON object
121143
let result = classDeclaration.accept(generator, parameters);
122144
return result;
145+
123146
}
124147

125148
/**
@@ -184,6 +207,11 @@ class Serializer {
184207
resource.validate();
185208
}
186209

210+
// Store the original JSON object to enable consditional retrieval later
211+
delete jsonObject.$networkId;
212+
resource.$original = jsonObject;
213+
Object.defineProperty(resource, '$original', { enumerable: false });
214+
187215
return resource;
188216
}
189217
}

packages/composer-common/lib/serializer/instancegenerator.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
const ClassDeclaration = require('../introspect/classdeclaration');
1818
const EnumDeclaration = require('../introspect/enumdeclaration');
1919
const Field = require('../introspect/field');
20-
// const leftPad = require('left-pad');
2120
const padStart = require('lodash.padstart');
2221
const ModelUtil = require('../modelutil');
2322
const RelationshipDeclaration = require('../introspect/relationshipdeclaration');

packages/composer-common/lib/serializer/jsonpopulator.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,25 @@ function isSystemProperty(name) {
3939
* @private
4040
*/
4141
function getAssignableProperties(resourceData) {
42-
return Object.keys(resourceData).filter((property) => {
43-
return !isSystemProperty(property) && !Util.isNull(resourceData[property]);
44-
});
42+
const assignable = [];
43+
for (const property in resourceData){
44+
if(!isSystemProperty(property) && !Util.isNull(resourceData[property])){
45+
assignable.push(property);
46+
}
47+
}
48+
return assignable;
4549
}
4650

4751
/**
4852
* Assert that all resource properties exist in a given class declaration.
49-
* @param {Array} properties Property names.
53+
* @param {Array} propertyNames Property names.
5054
* @param {ClassDeclaration} classDeclaration class declaration.
5155
* @throws {ValidationException} if any properties are not defined by the class declaration.
5256
* @private
5357
*/
54-
function validateProperties(properties, classDeclaration) {
58+
function validateProperties(propertyNames, classDeclaration) {
5559
const expectedProperties = classDeclaration.getProperties().map((property) => property.getName());
56-
const invalidProperties = properties.filter((property) => !expectedProperties.includes(property));
60+
const invalidProperties = propertyNames.filter((property) => !expectedProperties.includes(property));
5761
if (invalidProperties.length > 0) {
5862
const errorText = `Unexpected properties for type ${classDeclaration.getFullyQualifiedName()}: ` +
5963
invalidProperties.join(', ');
@@ -117,12 +121,12 @@ class JSONPopulator {
117121
const properties = getAssignableProperties(jsonObj);
118122
validateProperties(properties, classDeclaration);
119123

120-
properties.forEach((property) => {
124+
for (const property of properties) {
121125
const value = jsonObj[property];
122126
parameters.jsonStack.push(value);
123127
const classProperty = classDeclaration.getProperty(property);
124-
resourceObj[property] = classProperty.accept(this,parameters);
125-
});
128+
resourceObj[property] = classProperty.accept(this, parameters);
129+
}
126130

127131
return resourceObj;
128132
}
@@ -194,7 +198,7 @@ class JSONPopulator {
194198
classDeclaration.accept(this, parameters);
195199
}
196200
else {
197-
result = this.convertToObject(field,jsonItem);
201+
result = this.convertToObject(field, jsonItem);
198202
}
199203

200204
return result;

packages/composer-common/lib/util.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ class Util {
116116
if (transaction instanceof Resource){
117117
transaction.setIdentifier(txId.idStr);
118118
json = serializer.toJSON(transaction);
119-
120119
} else {
121120
transaction.transactionId = txId.idStr;
122121
json=transaction;

packages/composer-common/test/businessnetworkdefinition.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const moxios = require('moxios');
2323
const nodeUtil = require('util');
2424
const os = require('os');
2525
const path = require('path');
26+
const ReadOnlyDecorator = require('../lib/readonlydecorator');
2627
const ReturnsDecorator = require('../lib/returnsdecorator');
2728
const rimraf = nodeUtil.promisify(require('rimraf'));
2829

@@ -516,6 +517,18 @@ describe('BusinessNetworkDefinition', () => {
516517
decorator.should.be.an.instanceOf(ReturnsDecorator);
517518
});
518519

520+
it('should install the decorator processor for @readonly', () => {
521+
const bnd = new BusinessNetworkDefinition('id@1.0.0', 'description', null, 'readme');
522+
const modelManager = bnd.getModelManager();
523+
modelManager.addModelFile(`
524+
namespace org.acme
525+
@readonly
526+
transaction T{ }`);
527+
const transactionDeclaration = modelManager.getType('org.acme.T');
528+
const decorator = transactionDeclaration.getDecorator('readonly');
529+
decorator.should.be.an.instanceOf(ReadOnlyDecorator);
530+
});
531+
519532
});
520533

521534
});

0 commit comments

Comments
 (0)