diff --git a/packages/composer-common/api.txt b/packages/composer-common/api.txt index 59dc6b0e86..6ec6107523 100644 --- a/packages/composer-common/api.txt +++ b/packages/composer-common/api.txt @@ -260,7 +260,6 @@ class ModelManager { } class ReadOnlyDecorator extends Decorator { + void constructor(Object) throws IllegalModelException - + boolean getValue() } class ReadOnlyDecoratorFactory extends DecoratorFactory { + Decorator newDecorator(Object) diff --git a/packages/composer-common/changelog.txt b/packages/composer-common/changelog.txt index ce888d6b62..94df571d36 100644 --- a/packages/composer-common/changelog.txt +++ b/packages/composer-common/changelog.txt @@ -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 diff --git a/packages/composer-common/lib/readonlydecorator.js b/packages/composer-common/lib/readonlydecorator.js index 2ce9e94ad2..b8747044e2 100644 --- a/packages/composer-common/lib/readonlydecorator.js +++ b/packages/composer-common/lib/readonlydecorator.js @@ -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; } } diff --git a/packages/composer-common/test/businessnetworkdefinition.js b/packages/composer-common/test/businessnetworkdefinition.js index b7010e1f91..e582d67540 100644 --- a/packages/composer-common/test/businessnetworkdefinition.js +++ b/packages/composer-common/test/businessnetworkdefinition.js @@ -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'); diff --git a/packages/composer-common/test/readonlydecorator.js b/packages/composer-common/test/readonlydecorator.js index 2ba289262b..5aaacc4a22 100644 --- a/packages/composer-common/test/readonlydecorator.js +++ b/packages/composer-common/test/readonlydecorator.js @@ -20,7 +20,7 @@ const ModelManager = require('../lib/modelmanager'); require('chai').should(); -describe('RaedOnlyDecorator', () => { +describe('ReadOnlyDecorator', () => { let modelManager; let transactionDeclaration; @@ -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; - }); - - }); }); diff --git a/packages/composer-common/test/readonlydecoratorfactory.js b/packages/composer-common/test/readonlydecoratorfactory.js index 35fb39035f..06d723cd29 100644 --- a/packages/composer-common/test/readonlydecoratorfactory.js +++ b/packages/composer-common/test/readonlydecoratorfactory.js @@ -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); }); diff --git a/packages/composer-runtime/lib/engine.transactions.js b/packages/composer-runtime/lib/engine.transactions.js index 8091cddb66..e8858c08bf 100644 --- a/packages/composer-runtime/lib/engine.transactions.js +++ b/packages/composer-runtime/lib/engine.transactions.js @@ -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(); diff --git a/packages/composer-runtime/test/engine.transactions.js b/packages/composer-runtime/test/engine.transactions.js index 3edf8fa884..d7e1c26b37 100644 --- a/packages/composer-runtime/test/engine.transactions.js +++ b/packages/composer-runtime/test/engine.transactions.js @@ -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 } @@ -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', () => { @@ -668,7 +679,18 @@ 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'; @@ -676,21 +698,15 @@ describe('EngineTransactions', () => { 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', () => {