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

TypeReference.GetTypeProfiles() does not work correctly with FhirPath types. #2165

Open
ewoutkramer opened this issue Jul 28, 2022 · 1 comment
Labels
breaking change This issue/commit causes a breaking change, and requires a major version upgrade bug

Comments

@ewoutkramer
Copy link
Member

Describe the bug
The extension method GetTypeProfiles on TypeReference (in ElementDefinitionExtensions.cs) does not work with the situation in R4+ where the TypeRef.Code can contain a FhirPath primitive type.

There must be zillions of places where we just assume TypeRef.Code is a string with just a FHIR type, but this is no longer the case.

Expected behavior
I have written another implementation in the ElementSchema compiler:

  internal const string SYSTEMTYPEURI = "https://hl7.org/fhirpath/System.";
        internal const string SDXMLTYPEEXTENSION = "https://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";

        // TODO: This would probably be useful for the SDK too
        public static string GetCodeFromTypeRef(this ElementDefinition.TypeRefComponent typeRef)
        {
            // Note, in R3, this can be empty for system primitives (so the .value element of datatypes),
            // and there are some R4 profiles in the wild that still use this old schema too.
            if (string.IsNullOrEmpty(typeRef.Code))
            {
                var r3TypeIndicator = typeRef.CodeElement.GetStringExtension(SDXMLTYPEEXTENSION);
                if (r3TypeIndicator is null)
                    throw new IncorrectElementDefinitionException($"Encountered a typeref without a code.");

                return deriveSystemTypeFromXsdType(r3TypeIndicator);
            }
            else
                return typeRef.Code;

            static string deriveSystemTypeFromXsdType(string xsdTypeName)
            {
                // This R3-specific mapping is derived from the possible xsd types from the primitive datatype table
                // at https://www.hl7.org/fhir/stu3/datatypes.html, and the mapping of these types to
                // FhirPath from https://hl7.org/fhir/fhirpath.html#types
                return makeSystemType(xsdTypeName switch
                {
                    "xsd:boolean" => "Boolean",
                    "xsd:int" => "Integer",
                    "xsd:string" => "String",
                    "xsd:decimal" => "Decimal",
                    "xsd:anyURI" => "String",
                    "xsd:anyUri" => "String",
                    "xsd:base64Binary" => "String",
                    "xsd:dateTime" => "DateTime",
                    "xsd:gYear OR xsd:gYearMonth OR xsd:date" => "DateTime",
                    "xsd:gYear OR xsd:gYearMonth OR xsd:date OR xsd:dateTime" => "DateTime",
                    "xsd:time" => "Time",
                    "xsd:token" => "String",
                    "xsd:nonNegativeInteger" => "Integer",
                    "xsd:positiveInteger" => "Integer",
                    "xhtml:div" => "String", // used in R3 xhtml
                    _ => throw new NotSupportedException($"The xsd type {xsdTypeName} is not supported as a primitive type in R3.")
                });

                static string makeSystemType(string name) => SYSTEMTYPEURI + name;
            }
        }

        /// <summary>
        ///    Returns the profiles on the given Hl7.Fhir.Model.ElementDefinition.TypeRefComponent
        ///     if specified, or otherwise the core profile url for the specified type code.
        /// </summary>
        public static IEnumerable<string>? GetTypeProfilesCorrect(this ElementDefinition.TypeRefComponent elemType)
        {
            if (elemType == null) return null;

            if (elemType.Profile.Any()) return elemType.Profile;

            var type = elemType.GetCodeFromTypeRef();
            return new[] { Canonical.ForCoreType(type).Original };
        }

Note that this also needs us to merge the Canonical type from the serverless validator project with the SDK Canonical type (a good idea anyway).

@ewoutkramer
Copy link
Member Author

Although the chances are small that this influences current behaviour, doing this is a (minor) breaking change. Since it is also not really urgent, I will mark this issue as something to do for the next major release.

@ewoutkramer ewoutkramer added the breaking change This issue/commit causes a breaking change, and requires a major version upgrade label Jul 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change This issue/commit causes a breaking change, and requires a major version upgrade bug
Projects
None yet
Development

No branches or pull requests

2 participants