Skip to content

Commit

Permalink
feat(map): Add Introspection for Map Type (#646)
Browse files Browse the repository at this point in the history
* feat(map): add Type classes

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add test coverage

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update ModelFile with MapDeclaration

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update BaseModelManager - add getMapDeclarations()

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add type definitions

Signed-off-by: jonathan.casey <[email protected]>

* chore(changelog): updates change log

Signed-off-by: jonathan.casey <[email protected]>

* test(map): add more test cov for introspection

Signed-off-by: jonathan.casey <[email protected]>

* test(map): add test cov for modelmanager

Signed-off-by: jonathan.casey <[email protected]>

* chore(build): update package-lock

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): use descriptive names for key, value, property

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): extend from declaration

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): remove fqn reference from MapKey and MapValue

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): cleanup nested if

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add isMapDeclaration method

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): cleanup

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): remove unused test file

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add feature flag

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): MapKey & MapValue extend decorated

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): remove this.name references from MapKey & MapValue

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): support Asset, Participant, Transaction for  MapValue

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add more test coverage

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add test case for derived concept as MapValue

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add getFQN method to MapDeclaration

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update type definitions

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update changelog.txt, api.txt

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add test cov for feature flag

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): enable flag during test run

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update test coverage, fix toString

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update type definitions

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update changelog.txt, api.txt

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): bump test coverage

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add getParent to api for MapKey and MapValue

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): improve comment, fix typo

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update type definitions

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update changelog.txt, api.txt

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): remove hardcode metamodel version

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): fix comments

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): type assignment moved to constructor

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add explicit validation for MapValue

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): update changelog.txt, api.txt

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): remove boolean as a valid MapKey

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): bump test cov

Signed-off-by: jonathan.casey <[email protected]>

* feat(map): add test case bad value type

Signed-off-by: jonathan.casey <[email protected]>

---------

Signed-off-by: jonathan.casey <[email protected]>
  • Loading branch information
jonathan-casey authored May 22, 2023
1 parent 285ef29 commit 248a663
Show file tree
Hide file tree
Showing 52 changed files with 2,080 additions and 160 deletions.
336 changes: 178 additions & 158 deletions package-lock.json

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions packages/concerto-core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class BaseModelManager {
+ TransactionDeclaration[] getTransactionDeclarations()
+ EventDeclaration[] getEventDeclarations()
+ ParticipantDeclaration[] getParticipantDeclarations()
+ MapDeclaration[] getMapDeclarations()
+ EnumDeclaration[] getEnumDeclarations()
+ ConceptDeclaration[] getConceptDeclarations()
+ Factory getFactory()
Expand Down Expand Up @@ -97,6 +98,7 @@ class ClassDeclaration extends Declaration {
+ boolean isEvent()
+ boolean isConcept()
+ boolean isEnum()
+ boolean isMapDeclaration()
+ boolean isClassDeclaration()
}
class ConceptDeclaration extends ClassDeclaration {
Expand Down Expand Up @@ -151,6 +153,35 @@ class Introspector {
+ void constructor(ModelManager)
+ ClassDeclaration[] getClassDeclarations()
+ ClassDeclaration getClassDeclaration(String) throws Error
}
class MapDeclaration extends Declaration {
+ void constructor(ModelFile,Object) throws IllegalModelException
~ void validate() throws IllegalModelException
+ string getFullyQualifiedName()
+ ModelFile getModelFile()
+ string getName()
+ string getKey()
+ string getValue()
+ array getProperties()
+ String toString()
+ string declarationKind()
+ boolean isMapDeclaration()
}
class MapKeyType extends Decorated {
+ void constructor(MapDeclaration,Object,ModelFile) throws IllegalModelException
~ void validate() throws IllegalModelException
+ ModelFile getModelFile()
+ MapDeclaration getParent()
+ string getType()
+ String toString()
}
class MapValueType extends Decorated {
+ void constructor(MapDeclaration,Object) throws IllegalModelException
~ void validate() throws IllegalModelException
+ ModelFile getModelFile()
+ MapDeclaration getParent()
+ string getType()
+ String toString()
}
+ ModelManager newMetaModelManager()
+ object validateMetaModel()
Expand Down Expand Up @@ -179,6 +210,7 @@ class ModelFile extends Decorated {
+ ParticipantDeclaration[] getParticipantDeclarations()
+ ConceptDeclaration[] getConceptDeclarations()
+ EnumDeclaration[] getEnumDeclarations()
+ MapDeclaration[] getMapDeclarations()
+ ScalarDeclaration[] getScalarDeclarations()
+ Object[] getDeclarations(Function)
+ ClassDeclaration[] getAllDeclarations()
Expand Down
3 changes: 3 additions & 0 deletions packages/concerto-core/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 3.7.0 {a97cb6ebd45679354ba4da1940d2bb8d} 2023-05-19
- Add MapDeclaration, MapKeyType, AggregateValueType

Version 3.5.0 {b419dc1b3db9662d8c941a044cd8db5a} 2023-03-07
- Introduce Declaration type. ClassDeclaration and Scalar Declaration both extend Declaration.

Expand Down
10 changes: 10 additions & 0 deletions packages/concerto-core/lib/basemodelmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,16 @@ class BaseModelManager {
}, []);
}

/**
* Get the MapDeclarations defined in this model manager
* @return {MapDeclaration[]} the MapDeclaration defined in the model manager
*/
getMapDeclarations() {
return this.getModelFiles().reduce((prev, cur) => {
return prev.concat(cur.getMapDeclarations());
}, []);
}

/**
* Get the EnumDeclarations defined in this model manager
* @return {EnumDeclaration[]} the EnumDeclaration defined in the model manager
Expand Down
9 changes: 9 additions & 0 deletions packages/concerto-core/lib/introspect/classdeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,15 @@ class ClassDeclaration extends Declaration {
return this.type === `${MetaModelNamespace}.EnumDeclaration`;
}

/**
* Returns true if this class is the definition of a map.
*
* @return {boolean} true if the class is an asset
*/
isMapDeclaration() {
return this.type === `${MetaModelNamespace}.MapDeclaration`;
}

/**
* Returns true if this class is the definition of a enum.
*
Expand Down
185 changes: 185 additions & 0 deletions packages/concerto-core/lib/introspect/mapdeclaration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const { MetaModelNamespace } = require('@accordproject/concerto-metamodel');

const Declaration = require('./declaration');
const IllegalModelException = require('./illegalmodelexception');
const MapValueType = require('./mapvaluetype');
const MapKeyType = require('./mapkeytype');
const ModelUtil = require('../modelutil');

// Types needed for TypeScript generation.
/* eslint-disable no-unused-vars */
/* istanbul ignore next */
if (global === undefined) {
const ModelFile = require('./modelfile');
}

/**
* MapDeclaration defines a Map data structure, which allows storage of a collection
* of values, where each value is associated and indexed with a unique key.
*
* @extends Decorated
* @see See {@link Decorated}
* @class
* @memberof module:concerto-core
*/
class MapDeclaration extends Declaration {
/**
* Create an MapDeclaration.
* @param {ModelFile} modelFile - the ModelFile for this class
* @param {Object} ast - The AST created by the parser
* @throws {IllegalModelException}
*/
constructor(modelFile, ast) {
// TODO remove on full release.
if(process.env.ENABLE_MAP_TYPE !== 'true') {
throw new Error('MapType feature is not enabled. Please set the environment variable "ENABLE_MAP_TYPE=true" to access this functionality.');
}

super(modelFile, ast);
this.modelFile = modelFile;
this.process();
}

/**
* Process the AST and build the model
*
* @throws {IllegalModelException}
* @private
*/
process() {
super.process();

if (this.ast.properties.length !== 2) {
throw new IllegalModelException(`MapDeclaration must contain exactly two properties - MapKeyType & MapyValueType ${this.ast.name}`, this.modelFile, this.ast.location);
}

const key = this.ast.properties.find(property => property.$class === `${MetaModelNamespace}.MapKeyType`);
const value = this.ast.properties.find(property => property.$class === `${MetaModelNamespace}.AggregateValueType` || property.$class === `${MetaModelNamespace}.AggregateRelationshipValueType`);

if (!key) {
throw new IllegalModelException(`MapDeclaration must contain MapKeyType ${this.ast.name}`, this.modelFile, this.ast.location);
}

if (!value) {
throw new IllegalModelException(`MapDeclaration must contain AggregateValueType ${this.ast.name}`, this.modelFile, this.ast.location);
}

this.name = this.ast.name;
this.key = new MapKeyType(this, key);
this.value = new MapValueType(this, value);
this.fqn = ModelUtil.getFullyQualifiedName(this.modelFile.getNamespace(), this.ast.name);
}

/**
* Semantic validation of the structure of this class.
*
* @throws {IllegalModelException}
* @protected
*/
validate() {
super.validate();
this.key.validate();
this.value.validate();
}

/**
* Returns the fully qualified name of this class.
* The name will include the namespace if present.
*
* @return {string} the fully-qualified name of this class
*/
getFullyQualifiedName() {
return this.fqn;
}

/**
* Returns the ModelFile that defines this class.
*
* @public
* @return {ModelFile} the owning ModelFile
*/
getModelFile() {
return this.modelFile;
}

/**
* Returns the short name of a class. This name does not include the
* namespace from the owning ModelFile.
*
* @return {string} the short name of this class
*/
getName() {
return this.name;
}

/**
* Returns the type of the Map key property.
*
* @return {string} the Map key property
*/
getKey() {
return this.key;
}

/**
* Returns the type of the Map Value property.
*
* @return {string} the Map Value property
*/
getValue() {
return this.value;
}

/**
* Returns the MapDeclaration properties
*
* @return {array} the MapDeclaration properties
*/
getProperties() {
return this.ast.properties;
}

/**
* Returns the string representation of this class
* @return {String} the string representation of the class
*/
toString() {
return 'MapDeclaration {id=' + this.getFullyQualifiedName() + '}';
}

/**
* Returns the kind of declaration
*
* @return {string} what kind of declaration this is
*/
declarationKind() {
return 'MapDeclaration';
}

/**
* Returns true if this class is the definition of a class declaration.
*
* @return {boolean} true if the class is a class
*/
isMapDeclaration() {
return true;
}
}

module.exports = MapDeclaration;
Loading

0 comments on commit 248a663

Please sign in to comment.