Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core) Root hierarchy should have proper inheritance (v2) #240

Closed
wants to merge 3 commits into from
Closed
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
2 changes: 1 addition & 1 deletion packages/concerto-core/lib/introspect/classdeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ class ClassDeclaration extends Decorated {
* @returns {Boolean} true if the class declaration includes an explicit identifier
*/
isExplicitlyIdentified() {
return this.idField && this.idField !== '$identifier';
return (!!this.idField && this.idField !== '$identifier');
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ class IdentifiedDeclaration extends ClassDeclaration {
*/
process() {
super.process();

if(this.superType === 'Concept' && !this.idField) {
this.idField = '$identifier';
this.addIdentifierField();
}
}

/**
Expand Down
20 changes: 20 additions & 0 deletions packages/concerto-core/lib/introspect/modelfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ class ModelFile {

if(this.namespace !== 'concerto' && this.ast.imports) {
this.ast.imports.push( { namespace: 'concerto.Concept'} );
this.ast.imports.push( { namespace: 'concerto.Asset'} );
this.ast.imports.push( { namespace: 'concerto.Transaction'} );
this.ast.imports.push( { namespace: 'concerto.Participant'} );
this.ast.imports.push( { namespace: 'concerto.Event'} );
}

if(this.ast.imports) {
Expand All @@ -106,15 +110,31 @@ class ModelFile {
let thing = this.ast.body[n];

if(thing.type === 'AssetDeclaration') {
// Default super type for asset
if (!thing.classExtension) {
thing.classExtension = { class: { name: 'Asset' } };
}
this.declarations.push( new AssetDeclaration(this, thing) );
}
else if(thing.type === 'TransactionDeclaration') {
// Default super type for transaction
if (!thing.classExtension) {
thing.classExtension = { class: { name: 'Transaction' } };
}
this.declarations.push( new TransactionDeclaration(this, thing) );
}
else if(thing.type === 'EventDeclaration') {
// Default super type for event
if (!thing.classExtension) {
thing.classExtension = { class: { name: 'Event' } };
}
this.declarations.push( new EventDeclaration(this, thing) );
}
else if(thing.type === 'ParticipantDeclaration') {
// Default super type for participant
if (!thing.classExtension) {
thing.classExtension = { class: { name: 'Participant' } };
}
this.declarations.push( new ParticipantDeclaration(this, thing) );
}
else if(thing.type === 'EnumDeclaration') {
Expand Down
8 changes: 4 additions & 4 deletions packages/concerto-core/lib/modelmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ class ModelManager {
addRootModel() {
this.addModelFile( `namespace concerto
abstract concept Concept {}
abstract asset Asset {}
abstract transaction Transaction {}
abstract participant Participant {}
abstract event Event {}`, 'concerto.cto');
abstract concept Asset identified {}
abstract concept Transaction { o DateTime timestamp }
abstract concept Participant {}
abstract concept Event { o DateTime timestamp }`, 'concerto.cto');
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/concerto-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@
],
"all": true,
"check-coverage": true,
"statements": 99,
"branches": 98,
"statements": 98,
"branches": 97,
"functions": 99,
"lines": 98
}
Expand Down
16 changes: 8 additions & 8 deletions packages/concerto-core/test/introspect/classdeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,16 +212,16 @@ describe('ClassDeclaration', () => {
superclassName.should.equal('com.testing.parent.Super');
});

it('should return concerto.Concept when no super type exists', function() {
it('should return concerto.Participant when no super type exists', function() {
const baseclass = modelManager.getType('com.testing.parent.Base');
should.exist(baseclass);
const superclassName = baseclass.getSuperType();
should.equal(superclassName,'concerto.Concept');
should.equal(superclassName,'concerto.Participant');
});

it('toString',()=>{
const baseclass = modelManager.getType('com.testing.parent.Base');
baseclass.toString().should.equal('ClassDeclaration {id=com.testing.parent.Base super=Concept enum=false abstract=true}');
baseclass.toString().should.equal('ClassDeclaration {id=com.testing.parent.Base super=Participant enum=false abstract=true}');
});
});

Expand Down Expand Up @@ -280,7 +280,7 @@ describe('ClassDeclaration', () => {

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

it('should return Concept if no super type', () => {
it('should return Asset if no super type', () => {
let classDecl = modelManager.getType('system.Asset');
classDecl._resolveSuperType().should.not.be.null;
});
Expand All @@ -290,7 +290,7 @@ describe('ClassDeclaration', () => {
asset TestAsset identified by assetId { o String assetId }`);
let classDecl = modelManager.getType('org.acme.TestAsset');
let superClassDecl = classDecl._resolveSuperType();
should.equal(superClassDecl.getName(), 'Concept');
should.equal(superClassDecl.getName(), 'Asset');
});

it('should return the super class declaration for a super class in the same file', () => {
Expand Down Expand Up @@ -362,20 +362,20 @@ describe('ClassDeclaration', () => {
modelManager.addModelFiles(modelFiles);
});

it('should return an array with Concept if there are no superclasses', function() {
it('should return an array with Concept and Participant if there are no superclasses', function() {
const testClass = modelManager.getType('com.testing.parent.Base');
should.exist(testClass);
const superclasses = testClass.getAllSuperTypeDeclarations();
const superclassNames = superclasses.map(classDef => classDef.getName());
superclassNames.should.have.length(1);
superclassNames.should.have.length(2);
});

it('should return all superclass definitions', function() {
const testClass = modelManager.getType('com.testing.child.Sub');
should.exist(testClass);
const superclasses = testClass.getAllSuperTypeDeclarations();
const superclassNames = superclasses.map(classDef => classDef.getName());
superclassNames.should.have.same.members(['Base', 'Super', 'Concept']);
superclassNames.should.have.same.members(['Base', 'Super', 'Participant', 'Concept']);
});
});

Expand Down
15 changes: 5 additions & 10 deletions packages/concerto-core/test/introspect/identifieddeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ asset Order {
mm.addModelFile( `
namespace test

asset Order identified {
asset Order {
o Double price
}
`, 'test.cto');
Expand All @@ -92,7 +92,7 @@ asset Order identified by sku {

const order = mm.getType('test.Order');
order.should.not.be.null;
order.getProperties().length.should.equal(2);
order.getProperties().length.should.equal(3); // XXX Assets always have an identifier
order.getIdentifierFieldName().should.equal('sku');
order.isSystemIdentified().should.be.false;
order.isExplicitlyIdentified().should.be.true;
Expand Down Expand Up @@ -124,11 +124,7 @@ asset Order identified by sku {
mm.addModelFile( `
namespace test

asset Order identified {
o Double price
}

asset FancyOrder identified extends Order {
asset FancyOrder identified {
o String sku
}

Expand Down Expand Up @@ -205,10 +201,9 @@ asset Order identified by sku {

const order = mm.getType('test.Order');
order.should.not.be.null;
order.getProperties().length.should.equal(2);
order.isSystemIdentified().should.be.true;
order.getProperties().length.should.equal(2); // XXX Assets always have an identifier
order.isSystemIdentified().should.be.false;
order.isExplicitlyIdentified().should.be.false;
order.getIdentifierFieldName().should.equal('$identifier');
});

});
Expand Down
4 changes: 2 additions & 2 deletions packages/concerto-core/test/introspect/modelfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('ModelFile', () => {
};
sandbox.stub(parser, 'parse').returns(ast);
let mf = new ModelFile(modelManager, 'fake definitions');
mf.imports.should.deep.equal(['org.freddos', 'org.doge', 'concerto.Concept']);
mf.imports.should.deep.equal(['org.freddos', 'org.doge', 'concerto.Concept', 'concerto.Asset', 'concerto.Transaction', 'concerto.Participant', 'concerto.Event']);
});

it('should call the parser with the definitions and save imports with uris', () => {
Expand All @@ -101,7 +101,7 @@ describe('ModelFile', () => {
};
sandbox.stub(parser, 'parse').returns(ast);
let mf = new ModelFile(modelManager, 'fake definitions');
mf.imports.should.deep.equal(['org.doge', 'org.freddos.*', 'concerto.Concept']);
mf.imports.should.deep.equal(['org.doge', 'org.freddos.*', 'concerto.Concept', 'concerto.Asset', 'concerto.Transaction', 'concerto.Participant', 'concerto.Event']);
mf.getImportURI('org.freddos.*').should.equal('https://freddos.org/model.cto');
(mf.getImportURI('org.doge') === null).should.be.true;
});
Expand Down
2 changes: 1 addition & 1 deletion packages/concerto-core/test/model/concept.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('Concept', function () {
asset.invSets = [inventorySets];
const serializer = new Serializer(factory, modelManager);
const obj = serializer.toJSON(asset);
JSON.stringify(obj).should.equal('{"$class":"org.acme.biznet.MakerInventory","makerId":"123","invSets":[{"$class":"org.acme.biznet.InventorySets","Make":"Make","Model":"Model","invCount":10,"invType":"NEWBATCH"}]}');
JSON.stringify(obj).should.equal('{"$class":"org.acme.biznet.MakerInventory","makerId":"123","invSets":[{"$class":"org.acme.biznet.InventorySets","Make":"Make","Model":"Model","invCount":10,"invType":"NEWBATCH"}],"$identifier":"123"}');
});

it('should generate JSON for an asset that contains a concept', function () {
Expand Down
1 change: 1 addition & 0 deletions packages/concerto-core/test/model/resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ describe('Resource', function () {
resource.owner = modelManager.getFactory().newRelationship('org.acme.l1', 'Person', '123');
resource.toJSON().should.deep.equal({
$class: 'org.acme.l1.Car',
$identifier: '456',
owner: 'resource:org.acme.l1.Person#123',
vin: '456'
});
Expand Down
4 changes: 2 additions & 2 deletions packages/concerto-core/test/models/farm2fork.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('Farm2Fork Model', function() {
animal.should.not.be.null;
animal.getIdentifierFieldName().should.equal('identifier');
animal.getName().should.equal('Animal');
animal.getProperties().length.should.equal(9);
animal.getProperties().length.should.equal(10);

// validator, default
let identifierField = animal.getProperty('identifier');
Expand All @@ -74,7 +74,7 @@ describe('Farm2Fork Model', function() {
let txDecl = modelFile.getTransactionDeclaration('MoveAnimalToHolding');
txDecl.should.not.be.null;
txDecl.getName().should.equal('MoveAnimalToHolding');
txDecl.getProperties().length.should.equal(4);
txDecl.getProperties().length.should.equal(3); // XXX Should not have an identifier, but farmer + holding + timestamp
let holdingField = txDecl.getProperty('holding');
(holdingField !== null).should.be.true;
holdingField.getName().should.equal('holding');
Expand Down
8 changes: 4 additions & 4 deletions packages/concerto-core/test/models/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ describe('Test Model', function(){
let vehicle = modelFile.getAssetDeclaration('Vehicle');
vehicle.getIdentifierFieldName().should.equal('vin');
vehicle.getName().should.equal('Vehicle');
vehicle.getProperties().length.should.equal(16); // 15 from Vehicle, and 1 from Base
vehicle.getProperties().length.should.equal(17); // 15 from Vehicle, and 1 from Base, and one from $identifier

// validator, default
let vinField = vehicle.getProperty('vin');
Expand Down Expand Up @@ -302,7 +302,7 @@ describe('Test Model', function(){
let txDecl = modelFile.getTransactionDeclaration('VehicleTransferredToScrapMerchant');
txDecl.should.not.be.null;
txDecl.getName().should.equal('VehicleTransferredToScrapMerchant');
txDecl.getProperties().length.should.equal(4);
txDecl.getProperties().length.should.equal(3); // Should have 3: scarpMerchant, vehicle, timestamp
let scrapMerchantField = txDecl.getProperty('scrapMerchant');
(scrapMerchantField !== null).should.be.true;
scrapMerchantField.getName().should.equal('scrapMerchant');
Expand Down Expand Up @@ -340,7 +340,7 @@ describe('Test Model', function(){
const importNamespace = ModelUtil.getNamespace(element);
return modelManager.getModelFile(importNamespace);
});
imprts.length.should.equal(2);
imprts.length.should.equal(6); // XXX Now includes all concerto.* classes
modelFile.getImports().includes('composer.MyParticipant').should.equal(true);
});
});
Expand Down Expand Up @@ -379,7 +379,7 @@ describe('Test Model', function(){
const importNamespace = ModelUtil.getNamespace(element);
return modelManager.getModelFile(importNamespace);
});
imprts.length.should.equal(3);
imprts.length.should.equal(7); // XXX Now includes all concerto.* classes
});
});
});
3 changes: 3 additions & 0 deletions packages/concerto-core/test/models/wildcards.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ describe('Wildcards Model', function () {
};
const resource = serializer.fromJSON(json);
resource.assetId.should.equal('1');
resource.$identifier.should.equal('1');
resource.concept.gender.should.equal('FEMALE');
resource.participant.personId.should.equal('1');
resource.participant.firstName.should.equal('Alice');
Expand Down Expand Up @@ -102,6 +103,7 @@ describe('Wildcards Model', function () {
};
const resource = ergoSerializer.fromJSON(json);
resource.assetId.should.equal('1');
resource.$identifier.should.equal('1');
resource.concept.gender.should.equal('FEMALE');
resource.participant.personId.should.equal('1');
resource.participant.firstName.should.equal('Alice');
Expand All @@ -125,6 +127,7 @@ describe('Wildcards Model', function () {
json.should.deep.equal({
$class: 'org.acme.wildcards.MyAsset',
assetId: '1',
$identifier: '1',
concept: {
$class: 'org.acme.wildcards.MyConcept',
gender: 'FEMALE'
Expand Down
7 changes: 7 additions & 0 deletions packages/concerto-core/test/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ describe('Serializer', () => {
});
json.should.deep.equal({
$class: 'org.acme.sample.SampleAsset',
$identifier: '1',
assetId: '1',
owner: 'resource:org.acme.sample.SampleParticipant#[email protected]',
stringValue: 'the value',
Expand Down Expand Up @@ -182,6 +183,7 @@ describe('Serializer', () => {
});
json.should.deep.equal({
$class: 'org.acme.sample.SampleAsset',
$identifier: '1',
assetId: '1'
});
});
Expand All @@ -192,6 +194,7 @@ describe('Serializer', () => {
let json = serializer.toJSON(resource);
json.should.deep.equal({
$class: 'org.acme.sample.SampleAsset',
$identifier: '1',
assetId: '1'
});
});
Expand Down Expand Up @@ -230,6 +233,7 @@ describe('Serializer', () => {
});
json.should.deep.equal({
$class: 'org.acme.sample.SampleAsset',
$identifier: '1',
assetId: '1',
owner: 'resource:org.acme.sample.SampleParticipant#[email protected]',
stringValue: '',
Expand Down Expand Up @@ -267,6 +271,7 @@ describe('Serializer', () => {
let resource = serializer.fromJSON(json);
resource.should.be.an.instanceOf(Resource);
resource.assetId.should.equal('1');
resource.$identifier.should.equal('1');
resource.owner.should.be.an.instanceOf(Relationship);
resource.stringValue.should.equal('the value');
resource.doubleValue.should.equal(3.14);
Expand Down Expand Up @@ -345,6 +350,7 @@ describe('Serializer', () => {
let resource = serializer.fromJSON(json, { validate: false });
resource.should.be.an.instanceOf(Resource);
resource.assetId.should.equal('1');
resource.$identifier.should.equal('1');
resource.owner.should.be.an.instanceOf(Relationship);
should.equal(resource.stringValue, undefined);
});
Expand All @@ -359,6 +365,7 @@ describe('Serializer', () => {
let resource = serializer.fromJSON(json);
resource.should.be.an.instanceOf(Resource);
resource.assetId.should.equal('1');
resource.$identifier.should.equal('1');
resource.owner.should.be.an.instanceOf(Relationship);
should.equal(resource.stringValue, undefined);
});
Expand Down
Loading