Skip to content

Generate enum classes #10

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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open

Conversation

ellykits
Copy link
Collaborator

@ellykits ellykits commented Apr 30, 2025

Fixes #7

It's a good idea to open an issue first for discussion.

  • Tests pass
  • Appropriate changes to documentation are included in the PR

ellykits added 7 commits May 1, 2025 02:44
Content for enum classes are retrieved from ValuSet and CodeSet
Terminology resources. Some enums are generated as nested classes
in the generated FHIR models, if the element declared in the
StructureDefinition is not a common binding element. Example is
the NameUse enum class of class HumanName (used in Patient model).

Signed-off-by: Elly Kitoto <[email protected]>
Signed-off-by: Elly Kitoto <[email protected]>
Signed-off-by: Elly Kitoto <[email protected]>
@ellykits
Copy link
Collaborator Author

ellykits commented May 1, 2025

TBD:

  • Use the generated enum types
  • Some types in r4b and r5 require version 3 ValueSet & CodeSystem from r4
  • Refactor Code.of methods for Surrogate classes. (Should resolve the issues with running tests)
  • Fix usage of inherited enumarated codes like Count, Age, inheriting from Quantity. The inheriting class should use the Enum created in the parent class.

@jingtang10
Copy link
Collaborator

@ellykits this looks great so far - just a small comment first: i think the new schema files can be simplified. there's no need to include fields that we don't need from the spec's json files.

@ellykits ellykits closed this May 12, 2025
@ellykits ellykits reopened this May 12, 2025
ellykits added 4 commits May 13, 2025 00:41
Signed-off-by: Elly Kitoto <[email protected]>
Exclude geration of enum class for a class with conflicting
commong binding name.

Signed-off-by: Elly Kitoto <[email protected]>
@ellykits ellykits marked this pull request as ready for review May 12, 2025 22:51
@ellykits ellykits requested a review from jingtang10 May 12, 2025 22:54
@ellykits ellykits self-assigned this May 13, 2025
@jingtang10 jingtang10 requested a review from Copilot May 21, 2025 23:20
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for generating enum classes from FHIR value sets and improves the handling of element bindings. Key changes include the introduction of new schema data classes (ValueSet, Binding, etc.), updates to surrogate and model type generation to integrate enum types based on FHIR value sets, and enhancements to the FhirCodegen task for processing ValueSet and CodeSystem files.

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/schema/ValueSet.kt New schema definitions for ValueSet, Compose, and Include.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/schema/StructureDefinition.kt Added a new binding property and a related Binding data class.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/schema/MoreStructureDefinitions.kt Introduced constants and helper extensions for common binding and enum processing.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/FhirEnum.kt New file for FHIR enum representations.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/primitives/EnumerationTypeGenerator.kt Generates FHIR Enumeration types used in the model.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/SurrogateTypeSpecGenerator.kt Updated to pass through and handle value set mappings for enum generation.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/ModelTypeSpecGenerator.kt Modified to generate nested enum classes and adjust property types when enum types are present.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/FhirCodegenTask.kt Enhanced to include processing of ValueSet and CodeSystem files and to trigger enum generation.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/FhirCodegen.kt Updated method signatures to include new mapping parameters for enum generation.
fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/EnumTypeSpecGenerator.kt New generator for Kotlin enum types based on FHIR concepts and value sets.
Comments suppressed due to low confidence (1)

fhir-codegen/gradle-plugin/src/main/kotlin/com/google/fhir/codegen/schema/MoreStructureDefinitions.kt:241

  • [nitpick] Avoid using println for debugging in production code; consider using a structured logging framework to log diagnostic information.
println("Look here..... is the element" + Json { prettyPrint = true }.encodeToString(element))

fun Include.isValueSystemSupported(): Boolean =
!system.isNullOrBlank() &&
!system.startsWith("urn", ignoreCase = true) &&
system !in setOf("http://hl7.org/fhir/specimen-combined", "http://unitsofmeasure.org", true)
Copy link
Preview

Copilot AI May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The set passed to 'system !in setOf(...)' incorrectly includes a boolean value (true) among strings. Please remove the boolean value to ensure proper string comparisons.

Suggested change
system !in setOf("http://hl7.org/fhir/specimen-combined", "http://unitsofmeasure.org", true)
system !in setOf("http://hl7.org/fhir/specimen-combined", "http://unitsofmeasure.org")

Copilot uses AI. Check for mistakes.

Copy link
Collaborator

@jingtang10 jingtang10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some documentation to the README.md file.

I would suggest either modify the table in Mapping FHIR data structure to Kotlin section, or add a new section specifically about mapping enums.

import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.asTypeName

object EnumTypeSpecGenerator {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation

valueSet: ValueSet,
codeSystemMap: Map<String, CodeSystem>,
): TypeSpec? {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove empty line

Comment on lines +240 to +242
if (valueSetUrl == "http://hl7.org/fhir/ValueSet/specimen-combined") {
println("Look here..... is the element" + Json { prettyPrint = true }.encodeToString(element))
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the debugging code?

val version = packageName.substringAfterLast('.')
val isR5 = version.equals("r5", ignoreCase = true)

val superclassName = ClassName(packageName, if (isR5) "PrimitiveType" else "Element")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why's this?

.copy(nullable = true),
)
.addKdoc(
"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to pull these comments automatically from somewhere rather than hardcoding them?

if not, i'd write something a bit more generic/meta than this - focus on the fact that these are hand generated to match the parent class.

.apply {
fhirEnum.description?.sanitizeKDoc()?.let { addKdoc(it) }
primaryConstructor(
FunSpec.constructorBuilder().addParameter("code", String::class).build()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: should the enum values just include system, display, and definition fields?

addFunction(
FunSpec.builder("getSystem")
.addStatement("return %S", fhirEnum.getSystem() ?: "")
.returns(String::class)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: move the .returns up, since it's part of the function signature, and then addStatement

val constants: List<FhirEnumConstant> = emptyList(),
) {
fun getSystem(): String? {
return constants.firstOrNull()?.system
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this correct? does an enum always have the only one code system?

seems to me it can include multiple code systems.

import kotlinx.serialization.Serializable

@Serializable
data class FhirEnum(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this really belong in the schema package? seems to me this is an intermediary class rather than something you deserialise from the specification's' json files?

Comment on lines +157 to +158
if (valueSet.compose?.include.isNullOrEmpty()) return null
val includes = valueSet.compose.include.filter { it.isValueSystemSupported() }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can do something like

valueSet.compose?.include?.let {
  ...
}

to simplify the code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Generate enums correctly
2 participants