Example #1
0
        //$$$ 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);
        }
Example #2
0
        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);
        }
Example #3
0
        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;
                }
            }
        }