Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/composer-common/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ class ModelManager {
}
class ReadOnlyDecorator extends Decorator {
+ void constructor(Object) throws IllegalModelException
+ boolean getValue()
}
class ReadOnlyDecoratorFactory extends DecoratorFactory {
+ Decorator newDecorator(Object)
Expand Down
3 changes: 3 additions & 0 deletions packages/composer-common/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
# Note that the latest public API is documented using JSDocs and is available in api.txt.
#

Version 0.19.20 {308d962120667e982b2600107d0b8b13} 2019-01-29
- Modify readonly decorator to be parameterless

Version 0.19.20 {5ff216eab17b2d990c43636c51a585b5} 2018-12-18
- Add readonly decorator factory

Expand Down
17 changes: 2 additions & 15 deletions packages/composer-common/lib/readonlydecorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,9 @@ class ReadOnlyDecorator extends Decorator {
process() {
super.process();
const args = this.getArguments();
if (args.length !== 1) {
throw new IllegalModelException(`@readonly decorator expects 1 argument, but ${args.length} arguments were specified.`, this.parent.getModelFile(), this.ast.location);
if (args.length !== 0) {
throw new IllegalModelException(`@readonly decorator expects 0 arguments, but ${args.length} arguments were specified.`, this.parent.getModelFile(), this.ast.location);
}
const arg = args[0];
if (typeof arg !== 'boolean') {
throw new IllegalModelException(`@readonly decorator expects a boolean argument, but an argument of type ${typeof arg} was specified.`, this.parent.getModelFile(), this.ast.location);
}
this.value = arg;
}

/**
* Get the value of this commit decorator.
* @return {boolean} The value of this commit decorator.
*/
getValue() {
return this.value;
}

}
Expand Down
2 changes: 1 addition & 1 deletion packages/composer-common/test/businessnetworkdefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ describe('BusinessNetworkDefinition', () => {
const modelManager = bnd.getModelManager();
modelManager.addModelFile(`
namespace org.acme
@readonly(true)
@readonly
transaction T{ }`);
const transactionDeclaration = modelManager.getType('org.acme.T');
const decorator = transactionDeclaration.getDecorator('readonly');
Expand Down
32 changes: 3 additions & 29 deletions packages/composer-common/test/readonlydecorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const ModelManager = require('../lib/modelmanager');

require('chai').should();

describe('RaedOnlyDecorator', () => {
describe('ReadOnlyDecorator', () => {

let modelManager;
let transactionDeclaration;
Expand All @@ -37,38 +37,12 @@ describe('RaedOnlyDecorator', () => {

describe('#process', () => {

it('should throw if no arguments are specified', () => {
(() => {
new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [] } });
}).should.throw(/@readonly decorator expects 1 argument, but 0 arguments were specified. Line 1 column 1, to line 1 column 23./);
});

it('should throw if two arguments are specified', () => {
it('should throw if arguments are specified', () => {
(() => {
new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: true }, { value: false } ] } });
}).should.throw(/@readonly decorator expects 1 argument, but 2 arguments were specified. Line 1 column 1, to line 1 column 23./);
}).should.throw(/@readonly decorator expects 0 arguments, but 2 arguments were specified. Line 1 column 1, to line 1 column 23./);
});

it('should throw if a an incorrectly typed argument is specified', () => {
(() => {
new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: 'hello world' } ] } });
}).should.throw(/@readonly decorator expects a boolean argument, but an argument of type string was specified. Line 1 column 1, to line 1 column 23./);
});

});

describe('#getValue', () => {

it('should return true if the argument is true', () => {
const decorator = new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: true } ] } });
decorator.getValue().should.be.true;
});

it('should return false if the argument is false', () => {
const decorator = new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: false } ] } });
decorator.getValue().should.be.false;
});

});

});
2 changes: 1 addition & 1 deletion packages/composer-common/test/readonlydecoratorfactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('ReadOnlyDecoratorDecoratorFactory', () => {
});

it('should return a readonly decorator instance for a @readonly decorator', () => {
const decorator = factory.newDecorator(transactionDeclaration, { name: 'readonly', arguments: { list: [ { value: false } ] } });
const decorator = factory.newDecorator(transactionDeclaration, { name: 'readonly' });
decorator.should.be.an.instanceOf(ReadOnlyDecorator);
});

Expand Down
3 changes: 1 addition & 2 deletions packages/composer-runtime/lib/engine.transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,7 @@ class EngineTransactions {
// Get the type and resolved type.
const transactionDeclaration = transaction.getClassDeclaration();
const returnsDecorator = transactionDeclaration.getDecorator('returns');
const readOnlyDecorator = transactionDeclaration.getDecorator('readonly');
const readOnly = readOnlyDecorator ? readOnlyDecorator.getValue() : false;
const readOnly = transactionDeclaration.getDecorator('readonly') ? true : false;
const returnValueType = returnsDecorator.getType();
const returnValueResolvedType = returnsDecorator.getResolvedType();
const isArray = returnsDecorator.isArray();
Expand Down
42 changes: 29 additions & 13 deletions packages/composer-runtime/test/engine.transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ describe('EngineTransactions', () => {

}
@returns(MyAsset)
@readonly(true)
@readonly
transaction MyTransactionThatReturnsAsset {
o String value
}
@returns(MyAsset[])
@readonly(false)
@readonly
transaction MyTransactionThatReturnsAssetArray {
o String value
}
Expand Down Expand Up @@ -342,6 +342,17 @@ describe('EngineTransactions', () => {
})]).should.be.rejectedWith(/such error/);
});

it('should correctly identify a readonly decorator', () => {
let transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsConcept');
let result = transaction.getClassDeclaration().getDecorator('readonly');
should.not.exist(result);

transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsAsset');
result = transaction.getClassDeclaration().getDecorator('readonly');
should.exist(result);
result.name.should.equal('readonly');
});

});

describe('#_executeTransaction', () => {
Expand Down Expand Up @@ -668,29 +679,34 @@ describe('EngineTransactions', () => {
}]);
});

it('should handle a readonly(true) Asset return value', () => {
it('should handle a concept return value that is not readonly but contains a $original component', () => {
const transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsConcept');
const concept = factory.newConcept('org.acme', 'MyConcept');
concept.value = 'hello world';
concept.$original = 'not to be seen';
engine._processComplexReturnValue(mockContext, transaction, concept).should.deep.equal({
$class: 'org.acme.MyConcept',
value: 'hello world'
});
});

it('should handle a readonly Asset return value', () => {
const transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsAsset');
const asset = factory.newResource('org.acme', 'MyAsset','001');
asset.value = 'hello world';
asset.$original = 'penguin';
engine._processComplexReturnValue(mockContext, transaction, asset).should.equal('penguin');
});

it('should handle a readonly(false) Asset[] return value', () => {
it('should handle a readonly Asset[] return value', () => {
const transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsAssetArray');
const asset1 = factory.newResource('org.acme', 'MyAsset','001');
asset1.value = 'hello world';
asset1.$original = 'penguin';
const asset2 = factory.newResource('org.acme', 'MyAsset','002');
asset2.value = 'hello again world';
engine._processComplexReturnValue(mockContext, transaction, [asset1, asset2]).should.deep.equal([{
$class: 'org.acme.MyAsset',
assetId: '001',
value: 'hello world'
}, {
$class: 'org.acme.MyAsset',
assetId: '002',
value: 'hello again world'
}]);
asset2.$original = 'power';
engine._processComplexReturnValue(mockContext, transaction, [asset1, asset2]).should.deep.equal(['penguin', 'power']);
});

it('should throw for an invalid (wrong type) concept return value', () => {
Expand Down