-
Notifications
You must be signed in to change notification settings - Fork 250
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
Implement StructureMap-based extraction #566
Implement StructureMap-based extraction #566
Conversation
6e00788
to
323ffaf
Compare
976ead4
to
73748c5
Compare
@@ -126,6 +128,7 @@ object Dependencies { | |||
const val material = "1.3.0" | |||
const val retrofit = "2.7.2" | |||
const val truth = "1.0.1" | |||
const val hapiFhirValidations = "5.3.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alphabetical order please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also this can probably just be merged with the structures version number anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I'll change that
* Extract a FHIR resource from the [questionnaire] and [questionnaireResponse]. | ||
* | ||
* This method assumes there is only one FHIR resource to be extracted from the given | ||
* `questionnaire` and `questionnaireResponse`. | ||
* This method only supports definition-based extraction. StructureMap-based extraction will be | ||
* invoked if the [Questionnaire] declares a targetStructureMap extension. However, the returned | ||
* [Bundle] will be empty since the [StructureMapProvider] is not provided | ||
* | ||
* @return [Bundle] containing the extracted [Resource]s or empty Bundle if the extraction fails. | ||
* An exception might also be thrown in a few cases | ||
*/ | ||
fun extract(questionnaire: Questionnaire, questionnaireResponse: QuestionnaireResponse): Bundle { | ||
return extract(questionnaire, questionnaireResponse, null) | ||
} | ||
|
||
/** | ||
* Extract a FHIR resource from the [questionnaire] and [questionnaireResponse]. | ||
* | ||
* This method supports both Definition-based and StructureMap-based extraction. | ||
* StructureMap-based extraction will fail and an empty [Bundle] will be returned if the | ||
* [structureMapProvider] is not passed. | ||
*/ | ||
fun extract(questionnaire: Questionnaire, questionnaireResponse: QuestionnaireResponse): Base { | ||
fun extract( | ||
questionnaire: Questionnaire, | ||
questionnaireResponse: QuestionnaireResponse, | ||
structureMapProvider: StructureMapProvider? | ||
): Bundle { | ||
return if (questionnaire.targetStructureMap == null) | ||
extractByDefinitionBased(questionnaire, questionnaireResponse) | ||
else extractByStructureMapBased(questionnaire, questionnaireResponse, structureMapProvider) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you make the structure map provider an optional param in this API and merge these two functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, forgot about the Kotlin default param
structureMapProvider: StructureMapProvider? | ||
): Bundle { | ||
if (structureMapProvider == null) return Bundle() | ||
val pcm = FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val pcm = FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION) | |
val packageCacheManager = FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
val structureMapUrl = questionnaire.targetStructureMap ?: return Bundle() | ||
val structureMap = structureMapProvider.getStructureMap(structureMapUrl) | ||
|
||
val scu = StructureMapUtilities(contextR4) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val scu = StructureMapUtilities(contextR4) | |
val structureMapUtilities = StructureMapUtilities(contextR4) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
isCanRunWithoutTerminology = true | ||
} | ||
|
||
val structureMapUrl = questionnaire.targetStructureMap ?: return Bundle() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this has already been checked in the wrapper function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
@@ -461,7 +470,7 @@ class ResourceMapperTest { | |||
} | |||
|
|||
@Test | |||
fun `extract() should allow extracting with unanswered questions`() { | |||
fun `extract() should allow extracting correct Patient resource with unanswered questions using definition-based extraction`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fun `extract() should allow extracting correct Patient resource with unanswered questions using definition-based extraction`() { | |
fun `extract() should perform definition-based extraction with unanswered questions `() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
private fun String.toDateFromFormatYyyyMmDd(): Date? { | ||
return SimpleDateFormat("yyyy-MM-dd").parse(this) | ||
@Test | ||
fun `extract() should allow StructureMap-based extraction and return correct Patient resource`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fun `extract() should allow StructureMap-based extraction and return correct Patient resource`() { | |
fun `extract() should perform StructureMap-based extraction`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
""".trimIndent() | ||
|
||
val pcm = FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as before - avoid using abbreviations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// Package name manually checked from | ||
// https://simplifier.net/packages?Text=hl7.fhir.core&fhirVersion=All+FHIR+Versions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
val contextR4 = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1")) | ||
contextR4.isCanRunWithoutTerminology = true | ||
val scu = StructureMapUtilities(contextR4) | ||
val map: StructureMap = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did this map come from somewhere? or did you author this?
if it's an example from somewhere can you add a link? thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I authored this
- Refactor ResourceMapper#extract function to support both definition-based and StructureMap-based - Add interface to allow external implementation of fetching StructureMap - Add tests for StructureMap-based extraction - Add ca.uhn.hapi.fhir:org.hl7.fhir.validation:5.3.0 dependency for running tests - Change ResourceMapper#extract signature to return Bundle - Add overloaded ResourceMapper#extract method with extra StructureMapProvider param - Update ResourceMapperTest methods descriptions Fixes #543
- Use local version of hl7.fhir.r4.core provided with the library aar - Use private app storage as the local cache of the NPM package - Add zipping utility used to decompress package into private app storage - Fix test names in ResourceMapper
7eee7b5
to
890f9aa
Compare
/** | ||
* The map from the `name`s to `expression`s in the | ||
* [item extraction context extension](http://build.fhir.org/ig/HL7/sdc/StructureDefinition-sdc-questionnaire-itemExtractionContext.html) | ||
* s. | ||
*/ | ||
val Questionnaire.targetStructureMap: String? | ||
get() { | ||
val extensionValue = | ||
this.extension.singleOrNull { it.url == TARGET_STRUCTURE_MAP }?.value ?: return null | ||
return if (extensionValue is CanonicalType) extensionValue.valueAsString else null | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you create a new file called MoreQuestionnaires.kt
in the datacapture
package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
class ResourceMapperTest { | ||
@Test | ||
fun extract() { | ||
fun `extract() should allow perform definition-based extraction`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fun `extract() should allow perform definition-based extraction`() { | |
fun `extract() should perform definition-based extraction`() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
): Bundle { | ||
if (structureMapProvider == null || context == null) return Bundle() | ||
|
||
// Load the npm package |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this comment doesn't add much -- partly because the function has got a good name.
if you want to explain why this is needed, or how this is done, etc, please update this comment. otherwise, remove this comment if it's simply repeating the function name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
private fun extractByStructureMapBased( | ||
questionnaire: Questionnaire, | ||
questionnaireResponse: QuestionnaireResponse, | ||
structureMapProvider: StructureMapProvider?, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
structureMapProvider: StructureMapProvider?, | |
structureMapProvider: (String) -> StructureMap, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
interface StructureMapProvider { | ||
|
||
fun getStructureMap(fullUrl: String): StructureMap? | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/ResourceMapper.kt
Show resolved
Hide resolved
- The SimpleWorkerContext will only be loaded once
- Move Questionnaire extension to MoreQuestionnaire.kt file - Add tests for MoreQuestionnaire.kt and NpmPackageProvider.kt
return if (questionnaire.targetStructureMap == null) | ||
extractByDefinitionBased(questionnaire, questionnaireResponse) | ||
else | ||
extractByStructureMapBased( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extractByStructureMapBased( | |
extractByStructureMap( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds better. Done
context: Context? = null | ||
): Bundle { | ||
return if (questionnaire.targetStructureMap == null) | ||
extractByDefinitionBased(questionnaire, questionnaireResponse) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extractByDefinitionBased(questionnaire, questionnaireResponse) | |
extractByDefinitions(questionnaire, questionnaireResponse) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds better. Done
val structureMapUrl = questionnaire.targetStructureMap!! | ||
val structureMap = structureMapProvider(structureMapUrl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val structureMapUrl = questionnaire.targetStructureMap!! | |
val structureMap = structureMapProvider(structureMapUrl) | |
val structureMap = structureMapProvider(questionnaire.targetStructureMap!!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
import org.hl7.fhir.r4.context.SimpleWorkerContext | ||
import org.hl7.fhir.utilities.npm.NpmPackage | ||
|
||
object NpmPackageProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we leave this as public?
The whole initial setup process takes around 3 minutes on a good device and I plan to have this happening after installation and application start so that extraction is fast having done this previously.
The target application would have to setup the module after installation and load the modules at application start
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 minutes! that's mad... can you add a documentation here to say this process is very time consuming
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this is is already documented here.
I'll add extra documentation on the specific methods and some guiding documentation on the class itself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
general comment: the file IO functions should be suspend
functions
lateinit var npmPackage: NpmPackage | ||
lateinit var contextR4: SimpleWorkerContext | ||
|
||
fun loadSimpleWorkerContextWithPackage(context: Context): SimpleWorkerContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fun loadSimpleWorkerContextWithPackage(context: Context): SimpleWorkerContext { | |
fun loadSimpleWorkerContext(context: Context): SimpleWorkerContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/ResourceMapper.kt
Show resolved
Hide resolved
import org.hl7.fhir.r4.model.Questionnaire | ||
import org.junit.Test | ||
|
||
class MoreQuestionnairesKtTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class MoreQuestionnairesKtTest { | |
class MoreQuestionnairesTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, 🤦 my mistake
Assert.assertThrows(UninitializedPropertyAccessException::class.java) { | ||
NpmPackageProvider::contextR4.get() | ||
} | ||
|
||
val npmPackage = NpmPackageProvider.loadNpmPackage(ApplicationProvider.getApplicationContext()) | ||
|
||
NpmPackageProvider.loadSimpleWorkerContext(npmPackage) | ||
|
||
Truth.assertThat(NpmPackageProvider.contextR4).isNotNull() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are two test cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda but logically it's one. The aim of the test is make sure that the method loadSimpleWorkerContext
can initialize contextR4
when not previously initialized.
We need to confirm that contextR4
is not initialized before starting the test. Is this what you meant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think you can have a test case for the exception if you don't call the load function. and another test case for if you call the function.
these are fundamentally 2 different cases -- i think for unit tests we try to keep each test case really really simple and follows the 3 steps -> arrange act and assert.
here's some more background: https://livebook.manning.com/book/effective-unit-testing/chapter-4/112
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also import assertThat
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I'll remove the exception asserts in all the test cases and import assertThat
Assert.assertThrows(UninitializedPropertyAccessException::class.java) { | ||
NpmPackageProvider::npmPackage.get() | ||
} | ||
|
||
NpmPackageProvider.loadNpmPackage(ApplicationProvider.getApplicationContext()) | ||
|
||
Truth.assertThat(NpmPackageProvider.npmPackage).isNotNull() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again two test cases -- same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda but logically it's one. The aim of the test is make sure that the method loadSimpleWorkerContext
can initialize npmPackage
when not previously initialized.
We need to confirm that npmPackage
is not initialized before starting the test. Is this what you meant?
The same applies for the test below in loadSimpleWorkerContext() should cache SimpleWorkerContext
980799a
to
d535675
Compare
- The default package for the StructureMap is a Bundle. This is no longer inferred from the StructureMap. This helps support declaring multiple targets eg. Bundle, Patient, RelatedPerson
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still prefer to split the tests -- see comments in file
package com.google.android.fhir.datacapture.mapping | ||
|
||
/** Thrown to indicate that the FHIR core package could not be initialized successfully */ | ||
class NpmPackageInitializationError : RuntimeException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this should be a checked exception rather than unchecked. What's the reason to choose RuntimeException
instead of Exception
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
...apture/src/test/java/com/google/android/fhir/datacapture/utilities/NpmPackageProviderTest.kt
Outdated
Show resolved
Hide resolved
packageDirectory.delete() | ||
} | ||
|
||
Log.e(ResourceMapper::class.java.name, e.stackTraceToString()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure we need this if throwing exception - also strange to use ResourceMapper
class name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
* Provides utility for decompressing tar.gz or tgz files using the commons-io and commons-compress | ||
* libraries |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Provides utility for decompressing tar.gz or tgz files using the commons-io and commons-compress | |
* libraries | |
* Utilities for decompressing tar.gz or tgz files using the commons-io and commons-compress | |
* libraries. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
|
||
@Throws(IOException::class) | ||
fun decompress(compressedFilePath: String?, out: File?) { | ||
TarArchiveInputStream(GzipCompressorInputStream(FileInputStream(compressedFilePath))).use { fin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does fin
stand for? maybe use a more readable name?
TarArchiveInputStream(GzipCompressorInputStream(FileInputStream(compressedFilePath))).use { fin | |
TarArchiveInputStream(GzipCompressorInputStream(FileInputStream(compressedFilePath))).use { stream |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
* The whole process can take 1-2 minutes. | ||
*/ | ||
private fun setupNpmPackage(context: Context) { | ||
val filename = "packages.fhir.org-hl7.fhir.r4.core-4.0.1.tgz" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it a static const.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
IOUtils.closeQuietly(inputStream) | ||
IOUtils.closeQuietly(outputStream) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be in finally { ... }
block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
val structureMap = structureMapProvider(questionnaire.targetStructureMap!!) | ||
|
||
val structureMapUtilities = StructureMapUtilities(contextR4) | ||
val targetResource = Bundle() | ||
structureMapUtilities.transform(contextR4, questionnaireResponse, structureMap, targetResource) | ||
return targetResource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val structureMap = structureMapProvider(questionnaire.targetStructureMap!!) | |
val structureMapUtilities = StructureMapUtilities(contextR4) | |
val targetResource = Bundle() | |
structureMapUtilities.transform(contextR4, questionnaireResponse, structureMap, targetResource) | |
return targetResource | |
return Bundle().apply { | |
StructureMapUtilities(contextR4).transform(contextR4, questionnaireResponse, structureMapProvider(questionnaire.targetStructureMap!!), this) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
import org.hl7.fhir.r4.context.SimpleWorkerContext | ||
import org.hl7.fhir.utilities.npm.NpmPackage | ||
|
||
object NpmPackageProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
general comment: the file IO functions should be suspend
functions
lateinit var npmPackage: NpmPackage | ||
lateinit var contextR4: SimpleWorkerContext | ||
|
||
fun loadSimpleWorkerContext(context: Context): SimpleWorkerContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you call this function, you'll end up calling setupNpmPackage
without checking if it's been loaded before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question, setupNpmPackage
does the check itself and only proceeds if not previously loaded
Correct, we will generally want to change the ResourceMapper extraction functions to suspend functions |
6c55329
to
e3f77f1
Compare
e3f77f1
to
cc9f44e
Compare
datacapture/src/main/java/com/google/android/fhir/datacapture/utilities/NpmPackageProvider.kt
Outdated
Show resolved
Hide resolved
// Delete the folders | ||
val packageDirectory = File(outDir) | ||
if (packageDirectory.exists()) { | ||
packageDirectory.delete() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you handle it and add a logging statement?
val outDir = | ||
Environment.getDataDirectory().getAbsolutePath() + | ||
"/data/${context.applicationContext.packageName}/npm_packages/" | ||
return outDir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val outDir = | |
Environment.getDataDirectory().getAbsolutePath() + | |
"/data/${context.applicationContext.packageName}/npm_packages/" | |
return outDir | |
return | |
Environment.getDataDirectory().getAbsolutePath() + | |
"/data/${context.applicationContext.packageName}/npm_packages/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
) | ||
} | ||
|
||
/** Generate the path to the local npm packages directory */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** Generate the path to the local npm packages directory */ | |
/** Generates the path to the local npm packages directory. */ |
same with other function documentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
const val commonsCompress = "org.apache.commons:commons-compress:${Versions.commonsCompress}" | ||
const val commonsIo = "commons-io:commons-io:${Versions.commonsIo}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const val commonsCompress = "org.apache.commons:commons-compress:${Versions.commonsCompress}" | |
const val commonsIo = "commons-io:commons-io:${Versions.commonsIo}" | |
const val apacheCommonsCompress = "org.apache.commons:commons-compress:${Versions.apacheCommonsCompress}" | |
const val apacheCommonsIo = "commons-io:commons-io:${Versions.apacheCommonsIo}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
context: Context? | ||
): Bundle { | ||
if (structureMapProvider == null || context == null) return Bundle() | ||
val contextR4 = NpmPackageProvider.loadSimpleWorkerContext(context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val contextR4 = NpmPackageProvider.loadSimpleWorkerContext(context) | |
val simpleWorkerContext = NpmPackageProvider.loadSimpleWorkerContext(context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
contextR4, | ||
questionnaireResponse, | ||
structureMapProvider(questionnaire.targetStructureMap!!), | ||
this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it easier to read by annotating the params
contextR4, | |
questionnaireResponse, | |
structureMapProvider(questionnaire.targetStructureMap!!), | |
this | |
appInfo = simpleWorkerContext, | |
source = questionnaireResponse, | |
map = ..., | |
target = this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tried this and I get the error Named arguments are not allowed for non-Kotlin functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in that case add comments:
/* appInfo= */ simpleWorkerContext,
/* source= */ questionnaireResponse,
...
* loaded. | ||
*/ | ||
lateinit var npmPackage: NpmPackage | ||
lateinit var contextR4: SimpleWorkerContext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lateinit var contextR4: SimpleWorkerContext | |
lateinit var simpleWorkerContext: SimpleWorkerContext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (entry.isDirectory) { | ||
continue | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hold on - is this going to create an infinite loop if the entry is directory?
if (entry.isDirectory) { | |
continue | |
} | |
if (entry.isDirectory) { | |
entry = stream.nextTarEntry | |
continue | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, nice catch
import org.hl7.fhir.r4.context.SimpleWorkerContext | ||
import org.hl7.fhir.utilities.npm.NpmPackage | ||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking at this file i'm still slightly confused by the apis.
it still feels like it's doing too much. can we maybe have 2 classes
NpmPackageProvider
SimpleWorkerContextProvider
so in the former you have getNpmPackage(context: Context)
and in the latter you have getSimpleWorkerContext(context: Context)
. The latter depends on the former. And both caches what needs to be cached within themselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have split the functionalities into separate files
d8066ef
to
d8b9cb3
Compare
* | ||
* The operations takes 20 seconds to 1 minute. | ||
*/ | ||
fun loadSimpleWorkerContext(npmPackage: NpmPackage): SimpleWorkerContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you just get rid of this function? (i.e. inline it)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
really feels like one of these two apis can go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
* The whole process can take 1-3 minutes on a clean installation, otherwise, it should take 20 | ||
* seconds to 1 minute . | ||
*/ | ||
fun loadSimpleWorkerContext(context: Context): SimpleWorkerContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these need to be suspend functions. do you plan to do this in a follow up PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
*/ | ||
object SimpleWorkerContextProvider { | ||
|
||
lateinit var simpleWorkerContext: SimpleWorkerContext |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make this private -- the cache shouldn't be exposed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
) | ||
|
||
assertThat(generatedSimpleWorkerContext) | ||
.isEqualTo(SimpleWorkerContextProvider.simpleWorkerContext) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.isEqualTo(SimpleWorkerContextProvider.simpleWorkerContext) | |
.isEqualTo(SimpleWorkerContextProvider.loadSimpleWorkerContext()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
import org.robolectric.annotation.Config | ||
import org.robolectric.util.ReflectionHelpers | ||
|
||
@RunWith(RobolectricTestRunner::class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this class testing? is it not just testing your shadow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, at this point that's correct. I'm going to remove this and in case there any extra changes then you can point them out when you review again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! 👌
* Call [loadNpmPackage] to load it. The method handles skips the operation if it's already | ||
* loaded. | ||
*/ | ||
lateinit var npmPackage: NpmPackage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs to be private also
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Thanks 🙏 |
IMPORTANT: All PRs must be linked to an issue (except for extremely trivial and straightforward changes).
Fixes #543
Description
Alternative(s) considered
No, this is a FHIR SDC extraction specification
Type
Feature
Screenshots (if applicable)
NA
Checklist
./gradlew spotlessApply
and./gradlew spotlessCheck
to check my code follows the style guide of this project./gradlew check
and./gradlew connectedCheck
to test my changes locally