diff --git a/typescript/src/main/typescript/index.ts b/typescript/src/main/typescript/index.ts index e2255cc..97a4c06 100644 --- a/typescript/src/main/typescript/index.ts +++ b/typescript/src/main/typescript/index.ts @@ -595,49 +595,77 @@ export class OperandTypeResolverException extends DomainTypeResolverException { */ export class DomainModel { /** - * Returns the types of the domain model as map indexed by their type name. + * The types of the domain model as map indexed by their type name. */ - types: StringMap; + private types: StringMap; /** - * Returns the functions of the domain model as map indexed by their function name. + * The collection types of the domain model as map indexed by their type name. */ - functions: StringMap; + private collectionTypes: StringMap; + /** + * The functions of the domain model as map indexed by their function name. + */ + private functions: StringMap; /** * Returns the operation type resolvers of the domain model as map indexed by their type name. */ - operationTypeResolvers: StringMap>; + private operationTypeResolvers: StringMap>; /** * Returns the predicate type resolvers of the domain model as map indexed by their type name. */ - predicateTypeResolvers: StringMap>; + private predicateTypeResolvers: StringMap>; - private collectionTypes: StringMap; + private static readonly COLLECTION: CollectionDomainType = new CollectionDomainType("Collection", null); - constructor(types: StringMap, functions: StringMap, operationTypeResolvers: StringMap>, predicateTypeResolvers: StringMap>) { + constructor(types: StringMap, collectionTypes: StringMap, functions: StringMap, operationTypeResolvers: StringMap>, predicateTypeResolvers: StringMap>) { this.types = types; + this.collectionTypes = collectionTypes; this.functions = functions; this.operationTypeResolvers = operationTypeResolvers; this.predicateTypeResolvers = predicateTypeResolvers; - this.collectionTypes = {}; } - getType(input: string): DomainType { - if (input.startsWith("Collection")) { - let elementTypeName; - if (input.length == "Collection".length) { - elementTypeName = ""; - } else if (input.charAt("Collection".length) == '[') { - elementTypeName = input.substring("Collection".length, input.length - 1); - } else { - return this.types[input]; - } - if (this.collectionTypes[elementTypeName] !== undefined) { - return this.collectionTypes[elementTypeName]; - } else { - return this.collectionTypes[elementTypeName] = new CollectionDomainType(input, this.getType(elementTypeName)); + getType(typeName: string): DomainType { + return DomainModel.getType(typeName, this.types, this.collectionTypes); + } + + getFunction(typeName: string): DomainFunction { + return this.functions[typeName]; + } + + getOperationTypeResolvers(typeName: string): StringMap { + return this.operationTypeResolvers[typeName]; + } + + getOperationTypeResolver(typeName: string, operator: DomainOperator): DomainOperationTypeResolver { + return this.operationTypeResolvers[typeName][DomainOperator[operator]]; + } + + getPredicateTypeResolvers(typeName: string): StringMap { + return this.predicateTypeResolvers[typeName]; + } + + getPredicateTypeResolver(typeName: string, predicate: DomainPredicate): DomainPredicateTypeResolver { + return this.predicateTypeResolvers[typeName][DomainPredicate[predicate]]; + } + + private static getType(typeName: string, types: StringMap, collectionTypes: StringMap): DomainType { + if (typeName === undefined) { + return null; + } + if (typeName.startsWith("Collection")) { + if (typeName.length == "Collection".length) { + return DomainModel.COLLECTION; + } else if (typeName.charAt("Collection".length) == '[') { + let elementTypeName = typeName.substring("Collection".length + 1, typeName.length - 1); + if (collectionTypes[elementTypeName] !== undefined) { + return collectionTypes[elementTypeName]; + } else { + return collectionTypes[elementTypeName] = new CollectionDomainType(typeName, DomainModel.getType(elementTypeName, types, collectionTypes)); + } } } - return this.types[input]; + return types[typeName]; } /** @@ -903,6 +931,7 @@ export class DomainModel { }; let types = json['types'], functions = json['funcs'], opResolvers = json['opResolvers'], predResolvers = json['predResolvers']; var domainTypes: StringMap = {}; + var collectionTypes: StringMap = {}; var funcs: StringMap = {}; let operationTypeResolvers: StringMap> = {}; let predicateTypeResolvers: StringMap> = {}; @@ -960,8 +989,8 @@ export class DomainModel { newDomainType = new BasicDomainType(name, ops, preds, meta); break; case 'C': - newDomainType = new CollectionDomainType(name, null); - break; + // Ignore, since we build these types lazily + return; case 'U': newDomainType = new UnionDomainType(name, ops, preds, meta); break; @@ -1015,23 +1044,19 @@ export class DomainModel { if (Array.isArray(type['attrs'])) { type['attrs'].forEach(function (a) { let attrMeta = parseMeta(a['meta']); - entityType.attributes[a['name']] = new EntityAttribute(a['name'], domainTypes[a['type']], doc(attrMeta), attrMeta); + entityType.attributes[a['name']] = new EntityAttribute(a['name'], DomainModel.getType(a['type'], domainTypes, collectionTypes), doc(attrMeta), attrMeta); }); } break; case 'C': - let collectionType = domainTypes[name] as CollectionDomainType; - let prefix = 'Collection['; - if (name.length > prefix.length) { - collectionType.elementType = domainTypes[name.substring(prefix.length, name.length - 1)]; - } - break; + // Ignore, since we build these types lazily + return; case 'U': let unionType = domainTypes[name] as UnionDomainType; let unionElementTypeNames = unionType.name.split('|'); unionType.unionElements = []; for (const unionElementTypeName of unionElementTypeNames) { - unionType.unionElements.push(domainTypes[unionElementTypeName]) + unionType.unionElements.push(DomainModel.getType(unionElementTypeName, domainTypes, collectionTypes)) } break; } @@ -1048,14 +1073,14 @@ export class DomainModel { for (var i = 0; i < args.length; i++) { let param = args[i]; let paramMeta = parseMeta(param['meta']); - params.push(new DomainFunctionArgument(param['name'], i, domainTypes[param['type']], doc(paramMeta), paramMeta)); + params.push(new DomainFunctionArgument(param['name'], i, DomainModel.getType(param['type'], domainTypes, collectionTypes), doc(paramMeta), paramMeta)); } } let meta = parseMeta(func['meta']); let resultTypeResolver: DomainFunctionTypeResolver = resolver(func['typeResolver']); let resultType: DomainType = null; if (resultTypeResolver == null) { - resultType = domainTypes[func['type']]; + resultType = DomainModel.getType(func['type'], domainTypes, collectionTypes); resultTypeResolver = { resolveType(domainModel: DomainModel, domainFunction: DomainFunction, argumentTypes: DomainType[]): DomainType { validateArgumentTypes(domainFunction, argumentTypes); @@ -1143,6 +1168,7 @@ export class DomainModel { return new DomainModel( domainTypes, + collectionTypes, funcs, operationTypeResolvers, predicateTypeResolvers diff --git a/typescript/src/test/typescript/index.test.ts b/typescript/src/test/typescript/index.test.ts index e70aac6..4d14487 100644 --- a/typescript/src/test/typescript/index.test.ts +++ b/typescript/src/test/typescript/index.test.ts @@ -212,10 +212,10 @@ describe('Test parse ', function() { ], predResolvers: [] })); - expect(domainModel.types['Integer'].name).to.equal("Integer"); - expect((domainModel.types['Collection'] as domain.CollectionDomainType).elementType).to.equal(null); - let func = domainModel.functions['SIZE']; - expect(func.resultTypeResolver.resolveType(domainModel, func, [domainModel.types['Collection[Comment]']])).to.equal(domainModel.types['Integer']); + expect(domainModel.getType('Integer').name).to.equal("Integer"); + expect((domainModel.getType('Collection') as domain.CollectionDomainType).elementType).to.equal(null); + let func = domainModel.getFunction('SIZE'); + expect(func.resultTypeResolver.resolveType(domainModel, func, [domainModel.getType('Collection[Comment]')])).to.equal(domainModel.getType('Integer')); }); it('Real-model parse!', function() { @@ -744,8 +744,8 @@ describe('Test parse ', function() { } ] })); - expect(domainModel.types['Integer'].name).to.equal("Integer"); - expect(domainModel.operationTypeResolvers['Integer'][domain.DomainOperator[domain.DomainOperator.PLUS]].resolveType(domainModel, [domainModel.types['Integer'], domainModel.types['Integer']]).name).to.equal("Integer"); + expect(domainModel.getType('Integer').name).to.equal("Integer"); + expect(domainModel.getOperationTypeResolver('Integer', domain.DomainOperator.PLUS).resolveType(domainModel, [domainModel.getType('Integer'), domainModel.getType('Integer')]).name).to.equal("Integer"); }); it('With base model', function() { @@ -894,10 +894,10 @@ describe('Test parse ', function() { ], predResolvers: [] }), baseDomainModel); - expect(domainModel.types['Boolean']).to.equal(null); - expect((domainModel.types['Numeric'] as domain.BasicDomainType).enabledOperators.length).to.equal(1); - expect((domainModel.types['Numeric'] as domain.BasicDomainType).enabledPredicates.length).to.equal(1); - expect(domainModel.functions['indexOf']).to.equal(null); + expect(domainModel.getType('Boolean')).to.equal(null); + expect((domainModel.getType('Numeric') as domain.BasicDomainType).enabledOperators.length).to.equal(1); + expect((domainModel.getType('Numeric') as domain.BasicDomainType).enabledPredicates.length).to.equal(1); + expect(domainModel.getFunction('indexOf')).to.equal(null); }); });