From 871664100d40c945649b591458207bc9c224c744 Mon Sep 17 00:00:00 2001 From: Roman Nebeliuk Date: Wed, 21 May 2025 17:15:21 -0400 Subject: [PATCH 1/2] (feat): updated contact model with accord phoneNumber and email types --- src/dataModel/contact@1.0.0.cto | 67 +++++++++++++++++++++++++++++++++ src/dataModel/model.cto | 5 ++- src/db/Contact.json | 11 +++++- src/services/dataio.service.ts | 27 ++++++++++--- src/utils/modelManagerUtil.ts | 24 +++++++++--- 5 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 src/dataModel/contact@1.0.0.cto diff --git a/src/dataModel/contact@1.0.0.cto b/src/dataModel/contact@1.0.0.cto new file mode 100644 index 0000000..b25121a --- /dev/null +++ b/src/dataModel/contact@1.0.0.cto @@ -0,0 +1,67 @@ +/* + * 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. + */ +concerto version "^3.0.0" +namespace org.accordproject.contact@1.0.0 + +/* + * Definitions in this file do not enforce character constraints (for example, using + * regular expressions or digits). It is the responsibility of the application to enforce + * theseconstraints. This allows broader compatibility between systems and agreements which + * may have different requirements. + */ + +/* + * An email address without enclosing angle brackets + * + * Note: There is a restriction in RFC 2821 on the length of an + * address in MAIL and RCPT commands of 254 characters + * https://www.rfc-editor.org/errata_search.php?rfc=3696 + */ +scalar EmailAddress extends String length=[,254] + +/* + * A representation of telephone numbers to define commonly used structures + */ +concept PhoneNumber { + /* + * A formatted E.123 national number, potentially including spaces parentheses + * and separators (e.g. '-'). Does not include an International Prefix, extension, + * trunk prefix or alternate endings. + * https://www.itu.int/rec/T-REC-E.123-200102-I/en + */ + o String number length=[0,32] + + /* + * A standardized E.164 international telephone number without formatting such + * as spaces, parentheses or separators (e.g. '-'). Includes the International Prefix + * and Subscriber Number (National Destination Code and Base Number). Does not + * include an extension, trunk prefix or alternate endings. + * https://www.itu.int/rec/T-REC-E.164-201011-I/en + */ + o String normalizedNumber length=[,15] optional + + /* + * An E.164 Network Address Extension / Sub-address ("Ext.", Direct Dial In, + * or Direct Inward Dial) number. Does not include a "Ext." characters. + * https://www.itu.int/rec/T-REC-E.164-201011-I/en + */ + o String extension length=[0,6] optional + + /* + * The International Prefix or Country Code (CC) for the telephone number. Includes + * the leading '+' character or zeros. The International Prefix has 1-3 digits. + * https://www.itu.int/rec/T-REC-E.164-201011-I/en + */ + o String countryCode length=[0,7] optional +} \ No newline at end of file diff --git a/src/dataModel/model.cto b/src/dataModel/model.cto index 89bfadc..4c6ff54 100644 --- a/src/dataModel/model.cto +++ b/src/dataModel/model.cto @@ -1,4 +1,5 @@ namespace org.example@1.0.0 +import org.accordproject.contact@1.0.0.{EmailAddress, PhoneNumber} enum AccountType_Enum { o Prospect @@ -165,11 +166,11 @@ concept Contact identified by Id { @Term("Email") @Crud("Createable,Readable,Updateable") - o String email optional + o EmailAddress email optional @Term("Phone") @Crud("Createable,Readable,Updateable") - o String phone optional + o PhoneNumber phone optional @Term("Opportunity Link") @Crud("Createable,Readable,Updateable") diff --git a/src/db/Contact.json b/src/db/Contact.json index 65c3728..3b1a987 100644 --- a/src/db/Contact.json +++ b/src/db/Contact.json @@ -3,14 +3,21 @@ "Id": "1", "fullName": "Sarah Johnson", "email": "s.johnson@techcorp.com", - "phone": "+1-415-555-0193", + "phone": { + "number":"4155550193", + "countryCode":"1", + "extension":"999" + }, "currentOpportunity": "1" }, { "Id": "2", "fullName": "Michael Chen", "email": "m.chen@techcorp.com", - "phone": "+1-510-555-0176", + "phone": { + "number":"5105550176", + "countryCode":"1" + }, "currentOpportunity": "2" } ] diff --git a/src/services/dataio.service.ts b/src/services/dataio.service.ts index 13309d2..039290a 100644 --- a/src/services/dataio.service.ts +++ b/src/services/dataio.service.ts @@ -3,7 +3,7 @@ import { IReq, IRes } from '../utils/types'; import { QueryExecutor } from '../utils/queryExecutor'; import { FileDB } from '../db/fileDB'; import moment from 'moment'; -import { ConceptDeclaration, ModelManager } from '@accordproject/concerto-core'; +import { ConceptDeclaration, EnumDeclaration, MapDeclaration, ModelManager, ScalarDeclaration } from '@accordproject/concerto-core'; import path from 'path'; import { ModelManagerUtil } from '../utils/modelManagerUtil'; import { ResultRehydrator } from '../utils/resultRehydrator'; @@ -120,8 +120,8 @@ const generateErrorResponse = (message: string, code: string): ErrorResponse => * Concerto model manager setup using CTO file. * Model manager allowes users to load in CTO files and use Concerto model features directly in code. */ -const MODEL_MANAGER: ModelManager = ModelManagerUtil.createModelManagerFromCTO(path.join(__dirname, "../dataModel/model.cto")); -const CONCEPTS: ConceptDeclaration[] = MODEL_MANAGER.getConceptDeclarations(); +const MODEL_MANAGER: ModelManager = ModelManagerUtil.createModelManagerFromCTO(); +const CONCEPTS: ConceptDeclaration[] = MODEL_MANAGER.getModelFile("org.example@1.0.0").getConceptDeclarations(); const READABLE_CONCEPTS: ConceptDeclaration[] = CONCEPTS.filter(isReadableConcept); /** @@ -247,11 +247,26 @@ export const getTypeDefinitions = (req: IReq, res: IRes) if (!typeNames) { return res.status(400).json(generateErrorResponse(ErrorCode.BAD_REQUEST, 'Missing typeNames in request')).send(); } - MODEL_MANAGER.addCTOModel + try { + const modelFile = MODEL_MANAGER.getModelFile("org.example@1.0.0"); + return res.json({ - declarations: READABLE_CONCEPTS.map((concept: ConceptDeclaration) => concept.ast) - }) + declarations: [ + ...modelFile + .getEnumDeclarations() + .map((decl: EnumDeclaration) => decl.ast), + ...modelFile + .getScalarDeclarations() + .map((decl: ScalarDeclaration) => decl.ast), + ...modelFile + .getConceptDeclarations() + .map((decl: ConceptDeclaration) => decl.ast), + ...modelFile + .getMapDeclarations() + .map((decl: MapDeclaration) => decl.value.ast) + ] + }); } catch (err) { console.log(`Encountered an error getting type definitions: ${err.message}`); return res.status(500).json(generateErrorResponse(ErrorCode.INTERNAL_ERROR, err)).send(); diff --git a/src/utils/modelManagerUtil.ts b/src/utils/modelManagerUtil.ts index 65afab2..4fce0d3 100644 --- a/src/utils/modelManagerUtil.ts +++ b/src/utils/modelManagerUtil.ts @@ -3,17 +3,31 @@ import path from "path"; import fs from 'fs'; export class ModelManagerUtil { + private static DATA_MODELS_FOLDER: string = '../dataModel/'; + private static DATA_MODLS_FILES: string[] = [ + 'contact@1.0.0.cto', + 'model.cto', + ]; + /** * Create a ModelManager instance from a CTO file. - * @param {string} ctoFile - the path to the CTO file. * @return {ModelManager} a ModelManager instance. */ - public static createModelManagerFromCTO(ctoFile: string): ModelManager { + public static createModelManagerFromCTO(): ModelManager { // Needed as this is a workaround to skip line locations in generated AST // @ts-ignore - const modelManager: ModelManager = new ModelManager({ strict: true, skipLocationNodes: true }); - modelManager.addCTOModel(fs.readFileSync(path.join(__dirname, "../dataModel/model.cto"),'utf8')); + const modelManager: ModelManager = new ModelManager({ strict: true,skipLocationNodes: true }); + + this.DATA_MODLS_FILES.forEach((fileName: string) => { + modelManager.addCTOModel( + fs.readFileSync( + path.join(__dirname, `${this.DATA_MODELS_FOLDER}${fileName}`), + 'utf8' + ) + ); + }); + modelManager.validateModelFiles(); - return modelManager + return modelManager; } } \ No newline at end of file From 5f968c5ca544bf5417d1a6664c6d2cdde0567e59 Mon Sep 17 00:00:00 2001 From: Roman Nebeliuk Date: Thu, 22 May 2025 15:06:48 -0400 Subject: [PATCH 2/2] minor: fixed var name spelling --- src/utils/modelManagerUtil.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/modelManagerUtil.ts b/src/utils/modelManagerUtil.ts index 4fce0d3..53d49db 100644 --- a/src/utils/modelManagerUtil.ts +++ b/src/utils/modelManagerUtil.ts @@ -4,7 +4,7 @@ import fs from 'fs'; export class ModelManagerUtil { private static DATA_MODELS_FOLDER: string = '../dataModel/'; - private static DATA_MODLS_FILES: string[] = [ + private static DATA_MODELS_FILES: string[] = [ 'contact@1.0.0.cto', 'model.cto', ]; @@ -18,7 +18,7 @@ export class ModelManagerUtil { // @ts-ignore const modelManager: ModelManager = new ModelManager({ strict: true,skipLocationNodes: true }); - this.DATA_MODLS_FILES.forEach((fileName: string) => { + this.DATA_MODELS_FILES.forEach((fileName: string) => { modelManager.addCTOModel( fs.readFileSync( path.join(__dirname, `${this.DATA_MODELS_FOLDER}${fileName}`),