//$$$ Delete /// <summary> /// Traverse children using simple fhir path query. /// Return selected elements, or null if not found. /// </summary> public bool Generate(CodeBlockNested block, String methodModifiers, String methodName, ElementDefinitionNode node, String path, out Type leafType) { const String fcn = nameof(Generate); if (block is null) { throw new ArgumentNullException(nameof(block)); } if (methodModifiers is null) { throw new ArgumentNullException(nameof(methodModifiers)); } if (methodName is null) { throw new ArgumentNullException(nameof(methodName)); } if (node is null) { throw new ArgumentNullException(nameof(node)); } if (path is null) { throw new ArgumentNullException(nameof(path)); } //String fhirTypeName = node.FhirType.FriendlyName(); String fhirItemTypeName = node.FhirItemType.FriendlyName(); // we need to write header after we determine leaf node type. CodeBlockNested methodHeaderBlock = block.AppendBlock(); block .OpenBrace() .BlankLine() ; childBlock = block.AppendBlock(); String[] pathItems = path.Split('.'); Int32 i = 0; if (pathItems[0] == node.Name) { i += 1; } Int32 resultCounter = 0; leafType = null; String resultThis = "head"; while (i < pathItems.Length) { resultCounter += 1; String resultNext = $"result{resultCounter}"; String pathItem = pathItems[i++]; if (pathItem.StartsWith("resolve(")) { this.gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented"); return(false); } else if (pathItem.StartsWith("extension(\"")) { this.gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented"); return(false); } else if (pathItem.StartsWith("ofType(")) { this.gen.ConversionError(this.GetType().Name, fcn, $"TODO: FhirPath operator {pathItem} not implemented"); return(false); } else { if (node.TryGetAnyChild(pathItem, out ElementDefinitionNode next) == false) { this.gen.ConversionError(this.GetType().Name, fcn, $"Child {pathItem} not found"); return(false); } Type nodeType = node.FhirItemType; PropertyInfo childProperty = nodeType.GetPropertyByFhirName(pathItem); String childPropertyName = childProperty.Name; String childMethodName = GenerateGetChild(childPropertyName, nodeType, childProperty.PropertyType); block.AppendCode($"IEnumerable<{next.FhirItemType.FriendlyName()}> {resultNext} = {childMethodName}({resultThis});"); resultThis = resultNext; node = next; } } block .AppendCode($"return {resultThis};") .CloseBrace() ; leafType = node.FhirItemType; methodHeaderBlock .AppendCode($"{methodModifiers} IEnumerable<{leafType.FriendlyName()}> {methodName}(IEnumerable<{fhirItemTypeName}> head)") ; return(true); }
bool DefineSliceOnValueDiscriminator(Int32 index, CodeBlockNested sliceDiscriminators, ElementDefinitionNode sliceNode, String varName, ElementDefinition.DiscriminatorComponent discriminator, String valueFilterMethod, String leafType) { const String fcn = nameof(DefineSliceOnValueDiscriminator); var selectedNodes = sliceNode.Select(discriminator.Path).ToArray(); var fixedNodes = selectedNodes.FixedValues().ToArray(); Element fixedValue = fixedNodes.SingleOrDefault(); if (fixedValue == null) { this.gen.ConversionError(this.GetType().Name, fcn, $"Slice node lacks fixed element {discriminator.Path}"); return(false); } String sliceName = sliceNode.Element.SliceName; CodeBlockNested valueMethodBlock = sliceClassMethods.AppendBlock(); valueFilterMethod = CSMisc.ValueFilterName(CSMisc.MakePath(sliceNode.SlicePath(), discriminator.Path)); // Note: We are defining method here, after we know the return value type. valueMethodBlock .BlankLine() .SummaryOpen() .AppendCode($"/// Return all elements for discriminator # {index+1}'") .SummaryLines(discriminator.ToFormatedJson()) .SummaryClose() ; { GenerateFhirPathSearch g = new GenerateFhirPathSearch(this.gen); if (g.Generate(valueMethodBlock, "static", valueFilterMethod, elementNode, discriminator.Path, out Type leaf) == false) { return(false); } leafType = leaf.FriendlyName(); } String tempVarName = $"sliceOnValueDiscriminator"; sliceDiscriminators .OpenBrace() .AppendLine($"/// Define discriminator'") .AppendLines("/// ", discriminator.ToFormatedJson().ToLines()) .AppendCode($"var {tempVarName} = new SliceOnValueDiscriminator<{baseItemTypeName}, {leafType}>()") .OpenBrace() .AppendCode($"Path = \"{discriminator.Path}\",") .AppendCode($"ValueFilter = {valueFilterMethod}") .CloseBrace(";") ; ElementFixCode.Construct(sliceDiscriminators, fixedValue, $"{tempVarName}.Pattern", out String propertyType); sliceDiscriminators .AppendCode($"{varName} = {tempVarName};") .CloseBrace("") ; return(true); }
void DefineClassFields( CodeBlockNested subClassBlock, CodeBlockNested fieldsBlock, CodeBlockNested constructorBlock, CodeBlockNested writeBlock, ElementDefinition[] elements, String basePath, String className, ref Int32 index) { while (index < elements.Length) { ElementDefinition ed = elements[index]; // We know when we are at the end of a sub class, when the // path does no longer start with subPath. String path = ed.Path; if (ed.Path.StartsWith(basePath) == false) { return; } path = path.Substring(basePath.Length); String elementName = ElementName(ed.Path.LastPathPart()); fieldsBlock .AppendComment($"{index}. {elements[index].Path}") .AppendCode($"public ElementDefinitionInfo {elementName};") ; writeBlock .AppendCode($"{elementName}.Write(sDef);") ; Int32 min = 0; Int32 max = -1; if (ed.Min.HasValue) { min = ed.Min.Value; } if ((String.IsNullOrEmpty(ed.Max) == false) && (ed.Max != "*")) { max = Int32.Parse(ed.Max); } constructorBlock .OpenBrace() .AppendComment($"{index}. {elements[index].Path}") .AppendCode($"this.{elementName} = new ElementDefinitionInfo") .OpenBrace() .AppendCode($"Name = \"{elementName}\",") .AppendCode($"Path= \"{ed.Path}\",") .AppendCode($"Id = \"{ed.ElementId}\",") .AppendCode($"Min = {min},") .AppendCode($"Max = {max},") .AppendCode($"Types = new BaseType[]") .OpenBrace() .DefineBlock(out CodeBlockNested typesBlock) .CloseBrace("") .CloseBrace(";") .CloseBrace("") ; // If next elements starts with this items path, then this is a // subelement, so start creating sub class. if ( (index < elements.Length - 1) && (elements[index + 1].Path.StartsWith($"{ed.Path}.")) ) { String subClassName = TypeName(path.LastPathPart()); typesBlock .AppendCode($"new {subClassName}") .OpenBrace() .CloseBrace() ; DefineClass(subClassBlock, elements, ref index, ed.Path, subClassName, ComplexBase, out CodeBlockNested dummy); } else { for (Int32 typeIndex = 0; typeIndex < ed.Type.Count; typeIndex += 1) { String sep = typeIndex == (ed.Type.Count - 1) ? "" : ","; ElementDefinition.TypeRefComponent type = ed.Type[typeIndex]; switch (type.Code) { case null: break; case "boolean": case "integer": case "decimal": case "uri": case "string": case "base64Binary": case "instant": case "date": case "dateTime": case "time": case "oid": case "id": case "markdown": case "unsignedInt": case "positiveInt": case "xhtml": case "code": case "uuid": case "url": case "canonical": { String sep1 = ""; typesBlock .AppendCode($"new {PrimitiveNameSpace}.{PrimitiveName(type.Code)}") .OpenBrace() .AppendProfiles(type.Profile, ref sep1) .AppendTargetProfiles(type.TargetProfile, ref sep1) .CloseBrace(sep) ; } sep = ", "; break; case "CodeableConcept": case "Coding": { String sep1 = ""; typesBlock .AppendCode($"new {ComplexNameSpace}.{TypeName(type.Code)}") .OpenBrace() .AppendProfiles(type.Profile, ref sep1) .AppendTargetProfiles(type.TargetProfile, ref sep1) .CloseBrace(sep) ; } sep = ", "; break; case "Resource": { String sep1 = ""; typesBlock .AppendCode($"new {ResourceNameSpace}.{ResourceName(type.Code)}") .OpenBrace() .AppendProfiles(type.Profile, ref sep1) .AppendTargetProfiles(type.TargetProfile, ref sep1) .CloseBrace(sep) ; } sep = ", "; break; case "Reference": { String sep1 = ""; typesBlock .AppendCode($"new {ComplexNameSpace}.{TypeName(type.Code)}") .OpenBrace() .AppendProfiles(type.Profile, ref sep1) .AppendTargetProfiles(type.TargetProfile, ref sep1) .CloseBrace(sep) ; } sep = ", "; break; default: typesBlock .AppendCode($"new {ComplexNameSpace}.{TypeName(type.Code)}") .OpenBrace() .CloseBrace(sep) ; sep = ", "; break; } } index += 1; } } }