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

(feat) Functional API #188

Closed
wants to merge 12 commits into from
11 changes: 11 additions & 0 deletions packages/concerto-core/api.txt
Expand Up @@ -7,6 +7,16 @@ class BaseFileException extends BaseException {
+ string getShortMessage()
+ string getFileName()
}
+ void getTypeDeclaration()
+ string getIdentifier()
+ boolean isIdentifiable()
+ boolean isRelationship()
+ void setIdentifier()
+ string getFullyQualifiedIdentifier()
+ string toURI()
+ string getType()
+ string getNamespace()
+ boolean instanceOf()
class Factory {
+ void constructor(ModelManager)
+ Resource newResource(String,String,String,Object,boolean,String,boolean,boolean) throws TypeNotFoundException
Expand Down Expand Up @@ -220,3 +230,4 @@ class Serializer {
+ Resource fromJSON(Object,Object,boolean,boolean)
+ boolean hasInstance(object)
}
+ void validate() throws Error
3 changes: 3 additions & 0 deletions packages/concerto-core/changelog.txt
Expand Up @@ -24,6 +24,9 @@
# Note that the latest public API is documented using JSDocs and is available in api.txt.
#

Version 0.82.7 {a746636c9e994d3a89dd9377007b3a43} 2020-03-28
- Added functional API

Version 0.82.6 {03fa6481ffdf0e58cb110c6f24009d18} 2020-02-26
- Update JsDoc for ModelManager.addModelFiles

Expand Down
14 changes: 14 additions & 0 deletions packages/concerto-core/index.js
Expand Up @@ -52,3 +52,17 @@ module.exports.TransactionDeclaration = require('./lib/introspect/transactiondec
module.exports.Typed = require('./lib/model/typed');
module.exports.ModelUtil = require('./lib/modelutil');
module.exports.version = require('./package.json');

module.exports.Concerto = {
getTypeDeclaration : require('./lib/concerto').getTypeDeclaration,
getIdentifier : require('./lib/concerto').getIdentifier,
setIdentifier : require('./lib/concerto').setIdentifier,
getFullyQualifiedIdentifier : require('./lib/concerto').getFullyQualifiedIdentifier,
toURI : require('./lib/concerto').toURI,
getType : require('./lib/concerto').getType,
getNamespace : require('./lib/concerto').getNamespace,
instanceOf : require('./lib/concerto').instanceOf,
isIdentifiable : require('./lib/concerto').isIdentifiable,
isRelationship : require('./lib/concerto').isRelationship,
validate : require('./lib/validator').validate,
};
169 changes: 169 additions & 0 deletions packages/concerto-core/lib/concerto.js
@@ -0,0 +1,169 @@
/*
* 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 RESOURCE_SCHEME = 'resource';

/**
* Returns the ClassDeclaration for an object, or throws an exception
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @throw {Error} an error if the object does not have a $class attribute
* @return {*} the ClassDeclaration for the type
*/
function getTypeDeclaration(obj, modelManager) {
if(!obj.$class) {
throw new Error('Input object does not have a $class attribute.');
}

const typeDeclaration = modelManager.getType(obj.$class);

if(!typeDeclaration) {
throw new Error(`Type ${obj.$class} is not declared in the model manager`);
}

return typeDeclaration;
}

/**
* Gets the identifier for an object
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @return {string} The identifier for this object
*/
function getIdentifier(obj, modelManager) {
const typeDeclaration = getTypeDeclaration(obj, modelManager);
const idField = typeDeclaration.getIdentifierFieldName();
if(!idField) {
throw new Error('Object is not identifiable.');
}
return obj[idField];
}

/**
* Returns true if the object has an identifier
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @return {boolean} is the object has been defined with an identifier in the model
*/
function isIdentifiable(obj, modelManager) {
getTypeDeclaration(obj, modelManager);
const typeDeclaration = modelManager.getType(obj.$class);
const idField = typeDeclaration.getIdentifierFieldName();
return idField !== null;
}

/**
* Returns true if the object is a relationship
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @return {boolean} true if the object is a relationship
*/
function isRelationship(obj, modelManager) {
getTypeDeclaration(obj, modelManager);
return obj.$relationship === true;
}

/**
* Set the identifier for an object
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @param {string} id the new identifier
*/
function setIdentifier(obj, modelManager, id ) {
getTypeDeclaration(obj, modelManager);
const typeDeclaration = modelManager.getType(obj.$class);
const idField = typeDeclaration.getIdentifierFieldName();
obj[idField] = id;
}

/**
* Returns the fully qualified identifier for an object
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @returns {string} the fully qualified identifier
*/
function getFullyQualifiedIdentifier(obj, modelManager) {
getTypeDeclaration(obj, modelManager);
return `${obj.$class}#${getIdentifier(obj, modelManager)}`;
}

/**
* Returns a URI for an object
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @return {string} the URI for the object
*/
function toURI(obj, modelManager) {
getTypeDeclaration(obj, modelManager);
return `${RESOURCE_SCHEME}:${obj.$class}#${encodeURI(getIdentifier(obj, modelManager))}`;
}

/**
* Returns the short type name
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @returns {string} the short type name
*/
function getType(obj, modelManager) {
return getTypeDeclaration(obj, modelManager).getName();
}

/**
* Returns the namespace for the object
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @returns {string} the namespace
*/
function getNamespace(obj, modelManager) {
return getTypeDeclaration(obj, modelManager).getNamespace();
}

/**
* Check to see if this instance is an instance of the specified fully qualified
* type name.
* @param {*} obj the input object
* @param {*} modelManager the model manager
* @param {String} fqt The fully qualified type name.
* @returns {boolean} True if this instance is an instance of the specified fully
* qualified type name, false otherwise.
*/
function instanceOf(obj, modelManager, fqt) {
// Check to see if this is an exact instance of the specified type.
const classDeclaration = getTypeDeclaration(obj, modelManager);
if (classDeclaration.getFullyQualifiedName() === fqt) {
return true;
}
// Now walk the class hierachy looking to see if it's an instance of the specified type.
let superTypeDeclaration = classDeclaration.getSuperTypeDeclaration();
while (superTypeDeclaration) {
if (superTypeDeclaration.getFullyQualifiedName() === fqt) {
return true;
}
superTypeDeclaration = superTypeDeclaration.getSuperTypeDeclaration();
}
return false;
}

module.exports.getTypeDeclaration = getTypeDeclaration;
module.exports.getIdentifier = getIdentifier;
module.exports.setIdentifier = setIdentifier;
module.exports.getFullyQualifiedIdentifier = getFullyQualifiedIdentifier;
module.exports.toURI = toURI;
module.exports.getType = getType;
module.exports.getNamespace = getNamespace;
module.exports.instanceOf = instanceOf;
module.exports.isIdentifiable = isIdentifiable;
module.exports.isRelationship = isRelationship;