diff --git a/data/build.gradle.kts b/data/build.gradle.kts index a37ad1e..6851564 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -1,63 +1,93 @@ +import org.gradle.kotlin.dsl.invoke + plugins { - kotlin("jvm") + kotlin("multiplatform") kotlin("plugin.serialization") id("com.google.devtools.ksp") - // Apply the java-library plugin for API and implementation separation. - `java-library` + id("com.android.library") + id("de.jensklingenberg.ktorfit") version "2.6.4" +} + + +android { + namespace = "org.tidepool.data" + compileSdk = 34 + + defaultConfig { + minSdk = 26 + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } } kotlin { + androidTarget { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + } + } + compilerOptions { freeCompilerArgs.add("-Xcontext-parameters") } + + sourceSets { + val commonMain by getting { + dependencies { + implementation(project(":TidepoolKotlinAPI:domain")) + + // Ktorfit for networking + implementation("de.jensklingenberg.ktorfit:ktorfit-lib:2.6.4") + implementation("io.ktor:ktor-client-content-negotiation:3.3.1") + implementation("io.ktor:ktor-serialization-kotlinx-json:3.3.1") + implementation("io.ktor:ktor-client-logging:3.3.1") + + // Serialization + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") + + // Coroutines + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") + + + // Room KMP dependencies for local storage + implementation("androidx.room:room-runtime:2.8.1") + implementation("androidx.sqlite:sqlite-bundled:2.5.0") + + // Koin dependency injection + implementation("io.insert-koin:koin-core:4.1.0") + } + } + + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2") + implementation("io.insert-koin:koin-test:4.1.0") + } + } + + val androidMain by getting { + dependencies { + implementation("io.ktor:ktor-client-logging:3.3.1") + implementation("io.ktor:ktor-client-content-negotiation:3.3.1") + } + } + val androidUnitTest by getting + } } + repositories { mavenCentral() google() } dependencies { - implementation(project(":TidepoolKotlinAPI:domain")) - // Networking - implementation("com.squareup.retrofit2:retrofit:3.0.0") - implementation("com.squareup.okhttp3:okhttp:5.1.0") - - // Serialization - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") - implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0") - - // Coroutines - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") - - implementation("io.mcarle:konvert-api:4.3.2") - ksp("io.mcarle:konvert:4.3.2") - - // Room KMP dependencies for local storage - implementation("androidx.room:room-runtime:2.8.1") - implementation("androidx.sqlite:sqlite-bundled:2.5.0") - implementation("com.squareup.okhttp3:logging-interceptor:5.1.0") - add("ksp", "androidx.room:room-compiler:2.8.1") - - // Koin dependency injection - implementation("io.insert-koin:koin-core:4.1.0") - - // Testing - testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.2") - testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2") - testImplementation("com.squareup.okhttp3:mockwebserver:5.1.0") - testImplementation("io.insert-koin:koin-test:4.1.0") - - testRuntimeOnly("org.junit.platform:junit-platform-launcher") -} - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) - } -} - -tasks.named("test") { - useJUnitPlatform() + add("kspCommonMainMetadata", "androidx.room:room-compiler:2.8.1") + add("kspAndroid", "androidx.room:room-compiler:2.8.1") + add("kspCommonMainMetadata", "de.jensklingenberg.ktorfit:ktorfit-ksp:2.6.4") + add("kspAndroid", "de.jensklingenberg.ktorfit:ktorfit-ksp:2.6.4") } \ No newline at end of file diff --git a/data/src/androidMain/kotlin/org/tidepool/sdk/AndroidKeyValueStorage.kt b/data/src/androidMain/kotlin/org/tidepool/sdk/AndroidKeyValueStorage.kt new file mode 100644 index 0000000..e29cb34 --- /dev/null +++ b/data/src/androidMain/kotlin/org/tidepool/sdk/AndroidKeyValueStorage.kt @@ -0,0 +1,60 @@ +package org.tidepool.sdk + +import android.content.Context +import android.content.SharedPreferences +import org.tidepool.sdk.repository.KeyValueStorage + +class AndroidKeyValueStorage(context: Context) : KeyValueStorage { + private val preferences = context.getSharedPreferences("loop-kit-storage", Context.MODE_PRIVATE) + + override fun getString(key: String): String? = preferences.getString(key, null) + + override fun putString(key: String, value: String?) = preferences.edit(key, value) + + override fun getInt(key: String): Int? = if (preferences.contains(key)) { + preferences.getInt(key, 0) + } else { + null + } + + override fun putInt(key: String, value: Int?) = preferences.edit(key, value) + + override fun getLong(key: String): Long? = if (preferences.contains(key)) { + preferences.getLong(key, 0L) + } else { + null + } + + override fun putLong(key: String, value: Long?) = preferences.edit(key, value) + + override fun getFloat(key: String): Float? = if (preferences.contains(key)) { + preferences.getFloat(key, 0f) + } else { + null + } + + override fun putFloat(key: String, value: Float?) = preferences.edit(key, value) + + override fun getBoolean(key: String): Boolean? = if (preferences.contains(key)) { + preferences.getBoolean(key, false) + } else { + null + } + + override fun putBoolean(key: String, value: Boolean?) = preferences.edit(key, value) + + private fun SharedPreferences.edit( + key: String, + value: T?, + ) = edit().apply { + when (value) { + null -> remove(key) + is String -> putString(key, value) + is Int -> putInt(key, value) + is Long -> putLong(key, value) + is Float -> putFloat(key, value) + is Boolean -> putBoolean(key, value) + else -> throw IllegalArgumentException("Unsupported type") + } + }.apply() +} diff --git a/data/src/androidMain/kotlin/org/tidepool/sdk/di/DataModule.android.kt b/data/src/androidMain/kotlin/org/tidepool/sdk/di/DataModule.android.kt new file mode 100644 index 0000000..fe1bfa4 --- /dev/null +++ b/data/src/androidMain/kotlin/org/tidepool/sdk/di/DataModule.android.kt @@ -0,0 +1,61 @@ +package org.tidepool.sdk.di + +import androidx.room.Room +import androidx.sqlite.driver.bundled.BundledSQLiteDriver +import org.koin.core.module.Module +import org.koin.dsl.module +import org.tidepool.sdk.database.LoopKitDatabase +import org.tidepool.sdk.api.createAlertApi +import org.tidepool.sdk.api.createAuthorizationApi +import org.tidepool.sdk.api.createBlobApi +import org.tidepool.sdk.api.createClinicApi +import org.tidepool.sdk.api.createConfirmationApi +import org.tidepool.sdk.api.createDataApi +import org.tidepool.sdk.api.createGeneralApi +import org.tidepool.sdk.api.createMessageApi +import org.tidepool.sdk.api.createMetadataApi +import org.tidepool.sdk.api.createMetricsApi +import org.tidepool.sdk.api.createPrescriptionApi +import org.tidepool.sdk.api.createSummaryApi +import org.tidepool.sdk.api.createTaskApi +import org.tidepool.sdk.api.createUserApi +import de.jensklingenberg.ktorfit.Ktorfit +import io.ktor.client.plugins.logging.ANDROID +import io.ktor.client.plugins.logging.Logger +import org.tidepool.sdk.AndroidKeyValueStorage +import org.tidepool.sdk.repository.KeyValueStorage + +actual val platformDataModule: Module + get() = module { + single { + Room.databaseBuilder( + context = get(), + name = "loop-kit-database", + ) + .setDriver(BundledSQLiteDriver()) + .build() + } + single { + Logger.ANDROID + } + single { + AndroidKeyValueStorage(context = get()) + } + } + +actual fun provideAlertApi(ktorfit: Ktorfit) = ktorfit.createAlertApi() +actual fun provideAuthorizationApi(ktorfit: Ktorfit) = ktorfit.createAuthorizationApi() +actual fun provideBlobApi(ktorfit: Ktorfit) = ktorfit.createBlobApi() +actual fun provideClinicApi(ktorfit: Ktorfit) = ktorfit.createClinicApi() +actual fun provideConfirmationApi(ktorfit: Ktorfit) = ktorfit.createConfirmationApi() +actual fun provideDataApi(ktorfit: Ktorfit) = ktorfit.createDataApi() + +//actual fun provideExportApi(ktorfit: Ktorfit) = ktorfit.createExportApi() +actual fun provideGeneralApi(ktorfit: Ktorfit) = ktorfit.createGeneralApi() +actual fun provideMessageApi(ktorfit: Ktorfit) = ktorfit.createMessageApi() +actual fun provideMetadataApi(ktorfit: Ktorfit) = ktorfit.createMetadataApi() +actual fun provideMetricsApi(ktorfit: Ktorfit) = ktorfit.createMetricsApi() +actual fun providePrescriptionApi(ktorfit: Ktorfit) = ktorfit.createPrescriptionApi() +actual fun provideSummaryApi(ktorfit: Ktorfit) = ktorfit.createSummaryApi() +actual fun provideTaskApi(ktorfit: Ktorfit) = ktorfit.createTaskApi() +actual fun provideUserApi(ktorfit: Ktorfit) = ktorfit.createUserApi() \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/AuthenticationServerInternal.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/AuthenticationServerInternal.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/AuthenticationServerInternal.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/AuthenticationServerInternal.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/EnvironmentInternal.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/EnvironmentInternal.kt similarity index 61% rename from data/src/main/kotlin/org/tidepool/sdk/EnvironmentInternal.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/EnvironmentInternal.kt index b62ba8e..6f840d3 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/EnvironmentInternal.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/EnvironmentInternal.kt @@ -6,15 +6,15 @@ enum class EnvironmentInternal( val auth: AuthenticationServerInternal ) { - Production("https://api.tidepool.org", "tidepool", AuthenticationServerInternal.Production), + Production("https://api.tidepool.org/", "tidepool", AuthenticationServerInternal.Production), Integration( - "https://external.integration.tidepool.org", + "https://external.integration.tidepool.org/", "integration", AuthenticationServerInternal.External ), - Dev1("https://dev1.dev.tidepool.org", "dev", AuthenticationServerInternal.Development), - Qa1("https://qa1.development.tidepool.org", "qa1", AuthenticationServerInternal.QA), - Qa2("https://qa2.development.tidepool.org", "qa2", AuthenticationServerInternal.QA); + Dev1("https://dev1.dev.tidepool.org/", "dev", AuthenticationServerInternal.Development), + Qa1("https://qa1.development.tidepool.org/", "qa1", AuthenticationServerInternal.QA), + Qa2("https://qa2.development.tidepool.org/", "qa2", AuthenticationServerInternal.QA); } internal fun Environment.toInternal() = when (this) { diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/NetworkExceptions.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/NetworkExceptions.kt new file mode 100644 index 0000000..23f5e3c --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/NetworkExceptions.kt @@ -0,0 +1,21 @@ +package org.tidepool.sdk + +import io.ktor.client.plugins.ResponseException + +/** + * Helper function to map HttpException to specific Tidepool network exceptions + */ +fun ResponseException.toTidepoolException() = when (response.status.value) { + 400 -> BadRequestException("Bad request: ${message}", this) + 401 -> UnauthorizedException("Unauthorized: ${message}", this) + 403 -> ForbiddenException("Forbidden: ${message}", this) + 404 -> NotFoundException("Not found: ${message}", this) + 409 -> ConflictException("Conflict: ${message}", this) + 422 -> ValidationException("Validation error: ${message}", this) + 429 -> TooManyRequestsException("Too many requests: ${message}", this) + 500 -> InternalServerErrorException("Internal server error: ${message}", this) + 502 -> BadGatewayException("Bad gateway: ${message}", this) + 503 -> ServiceUnavailableException("Service unavailable: ${message}", this) + 504 -> GatewayTimeoutException("Gateway timeout: ${message}", this) + else -> UnknownNetworkException("HTTP ${response.status.value}: ${message}", this) +} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/RemoteExt.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/RemoteExt.kt similarity index 96% rename from data/src/main/kotlin/org/tidepool/sdk/RemoteExt.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/RemoteExt.kt index 9eef230..659a139 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/RemoteExt.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/RemoteExt.kt @@ -1,7 +1,8 @@ package org.tidepool.sdk +import io.ktor.client.plugins.ResponseException import kotlinx.coroutines.delay -import retrofit2.HttpException +import org.tidepool.sdk.dto.ResponseDto import java.io.IOException import java.net.ConnectException import java.net.SocketTimeoutException @@ -29,7 +30,7 @@ suspend fun runCatchingNetworkExceptions( block: suspend () -> T ): Result = try { Result.success(block()) -} catch (ex: HttpException) { +} catch (ex: ResponseException) { // Map HTTP exceptions to specific Tidepool exceptions Result.failure(ex.toTidepoolException()) } catch (ex: UnknownHostException) { @@ -69,9 +70,9 @@ suspend fun runWithRetry( onFailure = { if (maxRetries > 0 && it::class in retriableExceptions) { val jitteredDelay = delay + Random.nextLong(-delay / 10, delay / 10) - + delay(jitteredDelay) - + runWithRetry( block = block, maxRetries = maxRetries - 1, diff --git a/data/src/main/kotlin/org/tidepool/sdk/Session.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/Session.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/Session.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/Session.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/AlertApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/AlertApi.kt similarity index 63% rename from data/src/main/kotlin/org/tidepool/sdk/api/AlertApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/AlertApi.kt index 55778cc..22ae0ef 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/AlertApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/AlertApi.kt @@ -1,23 +1,23 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.alert.AlertConfigDto -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.Path +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Path interface AlertApi { - @GET("/v1/users/{userId}/followers/{followerUserId}/alerts") + @GET("v1/users/{userId}/followers/{followerUserId}/alerts") suspend fun getAlertsConfiguration( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Path("followerUserId") followerUserId: String ): AlertConfigDto - @POST("/v1/users/{userId}/followers/{followerUserId}/alerts") + @POST("v1/users/{userId}/followers/{followerUserId}/alerts") suspend fun upsertAlertsConfiguration( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -25,7 +25,7 @@ interface AlertApi { @Body alertsConfig: AlertConfigDto ) - @DELETE("/v1/users/{userId}/followers/{followerUserId}/alerts") + @DELETE("v1/users/{userId}/followers/{followerUserId}/alerts") suspend fun deleteAlertsConfiguration( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/AuthorizationApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/AuthorizationApi.kt similarity index 81% rename from data/src/main/kotlin/org/tidepool/sdk/api/AuthorizationApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/AuthorizationApi.kt index afe0c08..4732a89 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/AuthorizationApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/AuthorizationApi.kt @@ -2,11 +2,11 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.auth.ModifyUserPermissionsDto import org.tidepool.sdk.dto.metadata.users.PermissionsDto -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.Path +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Path /** * Authorization API interface based on the Tidepool Authorization API specification @@ -16,7 +16,7 @@ interface AuthorizationApi { /** * Retrieve all groups accessible to the user `userId` */ - @GET("/access/groups/{userId}") + @GET("access/groups/{userId}") suspend fun getGroupsForUser( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String @@ -25,7 +25,7 @@ interface AuthorizationApi { /** * Retrieve all users that have access to group `groupId` */ - @GET("/access/{groupId}") + @GET("access/{groupId}") suspend fun getUsersInGroup( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("groupId") groupId: String @@ -34,7 +34,7 @@ interface AuthorizationApi { /** * Retrieve permissions of individual user `userId` in group `groupId` */ - @GET("/access/{groupId}/{userId}") + @GET("access/{groupId}/{userId}") suspend fun getPermissionsForUser( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("groupId") groupId: String, @@ -46,7 +46,7 @@ interface AuthorizationApi { * The permissions provided in the request body replace all existing permissions for that user. * Therefore to delete a permission, submit the request body without that permission. */ - @POST("/access/{groupId}/{userId}") + @POST("access/{groupId}/{userId}") suspend fun grantPermissionsInGroup( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("groupId") groupId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/BlobApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/BlobApi.kt similarity index 61% rename from data/src/main/kotlin/org/tidepool/sdk/api/BlobApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/BlobApi.kt index a5b802f..54e7ef1 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/BlobApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/BlobApi.kt @@ -1,24 +1,22 @@ package org.tidepool.sdk.api -import okhttp3.RequestBody -import okhttp3.ResponseBody import org.tidepool.sdk.dto.blob.BlobMetadataDto import org.tidepool.sdk.dto.blob.BlobStatusDto import org.tidepool.sdk.dto.blob.DeviceLogContentDto import org.tidepool.sdk.dto.blob.DeviceLogsMetadataDto -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.Path -import retrofit2.http.Query +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query import java.time.Instant interface BlobApi { // Blob operations - @GET("/v1/users/{userId}/blobs") + @GET("v1/users/{userId}/blobs") suspend fun listBlobs( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -26,41 +24,41 @@ interface BlobApi { @Query("status") status: BlobStatusDto? = null, ): List - @POST("/v1/users/{userId}/blobs") - suspend fun createBlob( - @Header("X-Tidepool-Session-Token") sessionToken: String, - @Path("userId") userId: String, - @Header("Content-Type") contentType: String, - @Header("Digest") digest: String, - @Body content: RequestBody, - ): BlobMetadataDto +// @POST("v1/users/{userId}/blobs") +// suspend fun createBlob( +// @Header("X-Tidepool-Session-Token") sessionToken: String, +// @Path("userId") userId: String, +// @Header("Content-Type") contentType: String, +// @Header("Digest") digest: String, +// @Body content: RequestBody, +// ): BlobMetadataDto - @DELETE("/v1/users/{userId}/blobs") + @DELETE("v1/users/{userId}/blobs") suspend fun deleteAllBlobs( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, ) - @GET("/v1/blobs/{blobId}") + @GET("v1/blobs/{blobId}") suspend fun getBlobMetadata( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("blobId") blobId: String, ): BlobMetadataDto - @DELETE("/v1/blobs/{blobId}") + @DELETE("v1/blobs/{blobId}") suspend fun deleteBlob( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("blobId") blobId: String, ) - @GET("/v1/blobs/{blobId}/content") - suspend fun getBlobContent( - @Header("X-Tidepool-Session-Token") sessionToken: String, - @Path("blobId") blobId: String, - ): ResponseBody +// @GET("v1/blobs/{blobId}/content") +// suspend fun getBlobContent( +// @Header("X-Tidepool-Session-Token") sessionToken: String, +// @Path("blobId") blobId: String, +// ): ResponseBody // Device logs operations - @POST("/v1/users/{userId}/device_logs") + @POST("v1/users/{userId}/device_logs") suspend fun uploadDeviceLogs( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -70,7 +68,7 @@ interface BlobApi { @Body logs: List ): DeviceLogsMetadataDto - @GET("/v1/users/{userId}/device_logs") + @GET("v1/users/{userId}/device_logs") suspend fun listDeviceLogs( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/ClinicApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/ClinicApi.kt similarity index 78% rename from data/src/main/kotlin/org/tidepool/sdk/api/ClinicApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/ClinicApi.kt index c29bdf3..3fc320b 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/ClinicApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/ClinicApi.kt @@ -3,19 +3,19 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.clinic.ClinicDto import org.tidepool.sdk.dto.clinic.ClinicianDto import org.tidepool.sdk.dto.clinic.PatientDto -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.PATCH -import retrofit2.http.POST -import retrofit2.http.Path -import retrofit2.http.Query +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.PATCH +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query import java.time.Instant interface ClinicApi { - @GET("/v1/clinics") + @GET("v1/clinics") suspend fun listClinics( @Header("X-Tidepool-Session-Token") sessionToken: String, @Query("limit") limit: Int? = null, @@ -26,39 +26,39 @@ interface ClinicApi { @Query("ehrEnabled") ehrEnabled: Boolean? = null ): List - @POST("/v1/clinics") + @POST("v1/clinics") suspend fun createClinic( @Header("X-Tidepool-Session-Token") sessionToken: String, @Body clinic: ClinicDto ): ClinicDto - @GET("/v1/clinics/share_code/{shareCode}") + @GET("v1/clinics/share_code/{shareCode}") suspend fun getClinicByShareCode( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("shareCode") shareCode: String ): ClinicDto - @GET("/v1/clinics/{clinicId}") + @GET("v1/clinics/{clinicId}") suspend fun getClinic( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String ): ClinicDto - @PATCH("/v1/clinics/{clinicId}") + @PATCH("v1/clinics/{clinicId}") suspend fun updateClinic( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, @Body clinic: ClinicDto ): ClinicDto - @DELETE("/v1/clinics/{clinicId}") + @DELETE("v1/clinics/{clinicId}") suspend fun deleteClinic( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String ): Unit // Clinician endpoints - @GET("/v1/clinics/{clinicId}/clinicians") + @GET("v1/clinics/{clinicId}/clinicians") suspend fun getClinicClinicians( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, @@ -69,7 +69,7 @@ interface ClinicApi { @Query("role") role: String? = null ): List - @POST("/v1/clinics/{clinicId}/clinicians") + @POST("v1/clinics/{clinicId}/clinicians") suspend fun addClinicianToClinic( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, @@ -77,7 +77,7 @@ interface ClinicApi { ): ClinicianDto // Patient endpoints - @GET("/v1/clinics/{clinicId}/patients") + @GET("v1/clinics/{clinicId}/patients") suspend fun getClinicPatients( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, @@ -87,14 +87,14 @@ interface ClinicApi { @Query("sort") sort: String? = null ): List - @GET("/v1/clinics/{clinicId}/patients/{patientId}") + @GET("v1/clinics/{clinicId}/patients/{patientId}") suspend fun getClinicPatient( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, @Path("patientId") patientId: String ): PatientDto - @PATCH("/v1/clinics/{clinicId}/patients/{patientId}") + @PATCH("v1/clinics/{clinicId}/patients/{patientId}") suspend fun updateClinicPatient( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, @@ -102,7 +102,7 @@ interface ClinicApi { @Body patient: PatientDto ): PatientDto - @DELETE("/v1/clinics/{clinicId}/patients/{patientId}") + @DELETE("v1/clinics/{clinicId}/patients/{patientId}") suspend fun removePatientFromClinic( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/ConfirmationApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/ConfirmationApi.kt similarity index 78% rename from data/src/main/kotlin/org/tidepool/sdk/api/ConfirmationApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/ConfirmationApi.kt index df99b84..473aea1 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/ConfirmationApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/ConfirmationApi.kt @@ -7,55 +7,55 @@ import org.tidepool.sdk.dto.confirmation.ConfirmationLookupDto import org.tidepool.sdk.dto.confirmation.ConfirmationUpsertDto import org.tidepool.sdk.dto.confirmation.InvitationDto import org.tidepool.sdk.dto.confirmation.PasswordChangeDto -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path interface ConfirmationApi { // Account Signup Confirmations - @POST("/confirm/send/signup/{userId}") + @POST("confirm/send/signup/{userId}") suspend fun sendAccountSignupConfirmation( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Body requestBody: ConfirmationUpsertDto ) - @POST("/confirm/resend/signup/{email}") + @POST("confirm/resend/signup/{email}") suspend fun resendAccountSignup( @Path("email") email: String ) - @PUT("/confirm/accept/signup/{key}") + @PUT("confirm/accept/signup/{key}") suspend fun confirmAccountSignup( @Path("key") key: String, @Body requestBody: AcceptanceDto ) - @PUT("/confirm/dismiss/signup/{userId}") + @PUT("confirm/dismiss/signup/{userId}") suspend fun dismissAccountSignup( @Path("userId") userId: String, @Body requestBody: ConfirmationLookupDto ) - @GET("/confirm/signup/{userId}") + @GET("confirm/signup/{userId}") suspend fun getAccountSignupConfirmation( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String ): ConfirmationDto - @POST("/confirm/signup/{userId}") + @POST("confirm/signup/{userId}") suspend fun upsertAccountSignupConfirmation( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Body requestBody: ConfirmationUpsertDto ): ConfirmationDto - @PUT("/confirm/signup/{userId}") + @PUT("confirm/signup/{userId}") suspend fun cancelAccountSignupConfirmation( @Path("userId") userId: String, @Body requestBody: ConfirmationLookupDto @@ -63,39 +63,39 @@ interface ConfirmationApi { // Password Reset - @POST("/confirm/forgot/{email}") + @POST("confirm/forgot/{email}") suspend fun sendPasswordReset( @Path("email") email: String, @Body requestBody: JsonObject = JsonObject(content = emptyMap()), ) - @PUT("/confirm/accept/forgot") + @PUT("confirm/accept/forgot") suspend fun acceptPasswordChange( @Body requestBody: PasswordChangeDto ) // Care Team Invitations - @POST("/confirm/send/invite/{userId}") + @POST("confirm/send/invite/{userId}") suspend fun sendCareTeamInvite( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Body requestBody: InvitationDto ): ConfirmationDto - @GET("/confirm/invite/{userId}") + @GET("confirm/invite/{userId}") suspend fun getPendingCareTeamInvitations( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String ): List - @GET("/confirm/invitations/{userId}") + @GET("confirm/invitations/{userId}") suspend fun getReceivedInvitations( // TODO: this should return empty list, not error @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String ): List - @PUT("/confirm/accept/invite/{userId}/{invitedBy}") + @PUT("confirm/accept/invite/{userId}/{invitedBy}") suspend fun acceptCareTeamInvite( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -103,7 +103,7 @@ interface ConfirmationApi { @Body requestBody: ConfirmationLookupDto ) - @PUT("/confirm/dismiss/invite/{userId}/{invitedBy}") + @PUT("confirm/dismiss/invite/{userId}/{invitedBy}") suspend fun dismissInvite( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -111,7 +111,7 @@ interface ConfirmationApi { @Body requestBody: ConfirmationLookupDto ) - @PUT("/confirm/{userId}/invited/{invitedBy}") + @PUT("confirm/{userId}/invited/{invitedBy}") suspend fun cancelInvite( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/DataApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/DataApi.kt similarity index 73% rename from data/src/main/kotlin/org/tidepool/sdk/api/DataApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/DataApi.kt index 4681697..9d00ac6 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/DataApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/DataApi.kt @@ -5,19 +5,20 @@ import org.tidepool.sdk.dto.data.DataSetDto import org.tidepool.sdk.dto.data.DataSourceDto import org.tidepool.sdk.dto.data.NewDataSetDto import org.tidepool.sdk.dto.data.NewDataSourceDto -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import retrofit2.http.Query +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query +import org.tidepool.sdk.dto.ResponseDto import java.time.Instant interface DataApi { - @GET("/data/{userId}") + @GET("data/{userId}") suspend fun getDataForUser( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -31,9 +32,25 @@ interface DataApi { @Query("carelink") carelink: Boolean? = null, @Query("medtronic") medtronic: Boolean? = null, ): List + + @POST("data/{userId}") + suspend fun uploadDataForUser( + @Header("X-Tidepool-Session-Token") sessionToken: String, + @Path("userId") userId: String, + @Query("uploadId") uploadId: String? = null, + @Query("deviceId") deviceId: String? = null, + @Query("type", encoded = true) types: CommaSeparatedArray? = null, + @Query("startDate") startDate: Instant? = null, + @Query("endDate") endDate: Instant? = null, + @Query("latest") latest: Boolean? = null, + @Query("dexcom") dexcom: Boolean? = null, + @Query("carelink") carelink: Boolean? = null, + @Query("medtronic") medtronic: Boolean? = null, + @Body data: List, + ): List // Data Sets endpoints - @GET("/v1/users/{userId}/data_sets") + @GET("v1/users/{userId}/data_sets") suspend fun getUserDataSets( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -41,79 +58,79 @@ interface DataApi { @Query("size") size: Int? = null, ): List - @POST("/v1/users/{userId}/data_sets") + @POST("v1/users/{userId}/data_sets") suspend fun createDataSet( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Body newDataSet: NewDataSetDto ): DataSetDto - @GET("/v1/data_sets/{dataSetId}") + @GET("v1/data_sets/{dataSetId}") suspend fun getDataSet( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String ): DataSetDto - @PUT("/v1/data_sets/{dataSetId}") + @PUT("v1/data_sets/{dataSetId}") suspend fun updateDataSet( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String, @Body dataSet: DataSetDto ): DataSetDto - @DELETE("/v1/data_sets/{dataSetId}") + @DELETE("v1/data_sets/{dataSetId}") suspend fun deleteDataSet( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String ) - @POST("/v1/data_sets/{dataSetId}/data") + @POST("v1/data_sets/{dataSetId}/data") suspend fun uploadDataToDataSet( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String, @Body data: List, - ): List + ): ResponseDto - @DELETE("/v1/data_sets/{dataSetId}/data") + @DELETE("v1/data_sets/{dataSetId}/data") suspend fun deleteDataSetData( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String, ) // Legacy datasets endpoints - @GET("/v1/users/{userId}/datasets") + @GET("v1/users/{userId}/datasets") suspend fun getUserDataSetsLegacy( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, ): List - @POST("/v1/users/{userId}/datasets") + @POST("v1/users/{userId}/datasets") suspend fun createDataSetLegacy( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Body newDataSet: NewDataSetDto, ): DataSetDto - @GET("/v1/datasets/{dataSetId}") + @GET("v1/datasets/{dataSetId}") suspend fun getDataSetLegacy( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String, ): DataSetDto - @PUT("/v1/datasets/{dataSetId}") + @PUT("v1/datasets/{dataSetId}") suspend fun updateDataSetLegacy( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String, @Body dataSet: DataSetDto ): DataSetDto - @DELETE("/v1/datasets/{dataSetId}") + @DELETE("v1/datasets/{dataSetId}") suspend fun deleteDataSetLegacy( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String, ) - @POST("/v1/datasets/{dataSetId}/data") + @POST("v1/datasets/{dataSetId}/data") suspend fun uploadDataToDataSetLegacy( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSetId") dataSetId: String, @@ -121,7 +138,7 @@ interface DataApi { ): List // Data Sources endpoints - @GET("/v1/users/{userId}/data_sources") + @GET("v1/users/{userId}/data_sources") suspend fun getUserDataSources( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -129,52 +146,45 @@ interface DataApi { @Query("size") size: Int? = null, ): List - @POST("/v1/users/{userId}/data_sources") + @POST("v1/users/{userId}/data_sources") suspend fun createDataSource( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Body newDataSource: NewDataSourceDto, ): DataSourceDto - @DELETE("/v1/users/{userId}/data_sources") + @DELETE("v1/users/{userId}/data_sources") suspend fun deleteAllDataSources( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, ) - @GET("/v1/data_sources/{dataSourceId}") + @GET("v1/data_sources/{dataSourceId}") suspend fun getDataSource( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSourceId") dataSourceId: String, ): DataSourceDto - @PUT("/v1/data_sources/{dataSourceId}") + @PUT("v1/data_sources/{dataSourceId}") suspend fun updateDataSource( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSourceId") dataSourceId: String, @Body dataSource: DataSourceDto, ): DataSourceDto - @DELETE("/v1/data_sources/{dataSourceId}") + @DELETE("v1/data_sources/{dataSourceId}") suspend fun deleteDataSource( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("dataSourceId") dataSourceId: String, ) // Additional data endpoints - @DELETE("/v1/users/{userId}/data") + @DELETE("v1/users/{userId}/data") suspend fun deleteAllUserData( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, ) - @POST("/v1/users/{userId}/data") - suspend fun uploadData( - @Header("X-Tidepool-Session-Token") sessionToken: String, - @Path("userId") userId: String, - @Body data: List, - ): List - class CommaSeparatedArray(private vararg val types: T) { override fun toString(): String { diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/api/ExportApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/ExportApi.kt new file mode 100644 index 0000000..4442953 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/ExportApi.kt @@ -0,0 +1,20 @@ +package org.tidepool.sdk.api + +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query +import java.time.Instant + +interface ExportApi { + +// @GET("export/{userId}") +// suspend fun exportUserData( +// @Header("X-Tidepool-Session-Token") sessionToken: String, +// @Path("userId") userId: String, +// @Query("startDate") startDate: Instant? = null, +// @Query("endDate") endDate: Instant? = null, +// @Query("format") format: String = "xlsx", +// @Query("bgUnits") bgUnits: String = "mmol/L" +// ): ResponseBody +} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/GeneralApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/GeneralApi.kt similarity index 82% rename from data/src/main/kotlin/org/tidepool/sdk/api/GeneralApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/GeneralApi.kt index b14d28d..aa0d679 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/GeneralApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/GeneralApi.kt @@ -1,7 +1,7 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.general.MinimumClientVersionsDto -import retrofit2.http.GET +import de.jensklingenberg.ktorfit.http.GET interface GeneralApi { diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/MessageApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/MessageApi.kt similarity index 75% rename from data/src/main/kotlin/org/tidepool/sdk/api/MessageApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/MessageApi.kt index 371ebf8..f044d46 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/MessageApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/MessageApi.kt @@ -5,18 +5,18 @@ import org.tidepool.sdk.dto.message.MessageDto import org.tidepool.sdk.dto.message.MessageListDto import org.tidepool.sdk.dto.message.MessageResponseDto import org.tidepool.sdk.dto.message.NewMessageDto -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import retrofit2.http.Query +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query interface MessageApi { - @GET("/message/all/{userId}") + @GET("message/all/{userId}") suspend fun listAllMessages( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -24,7 +24,7 @@ interface MessageApi { @Query("endtime") endTime: String? = null, ): MessageListDto - @GET("/message/notes/{userId}") + @GET("message/notes/{userId}") suspend fun listTopLevelMessages( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -32,40 +32,40 @@ interface MessageApi { @Query("endtime") endTime: String? = null, ): MessageListDto - @POST("/message/send/{userId}") + @POST("message/send/{userId}") suspend fun createMessage( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Body requestBody: NewMessageDto, ): MessageResponseDto - @POST("/message/reply/{messageId}") + @POST("message/reply/{messageId}") suspend fun replyToMessage( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("messageId") messageId: String, @Body requestBody: NewMessageDto, ): MessageResponseDto - @GET("/message/read/{messageId}") + @GET("message/read/{messageId}") suspend fun findMessageById( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("messageId") messageId: String, ): MessageDto - @GET("/message/thread/{messageId}") + @GET("message/thread/{messageId}") suspend fun getMessageThread( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("messageId") messageId: String, ): MessageListDto - @PUT("/message/edit/{messageId}") + @PUT("message/edit/{messageId}") suspend fun updateMessage( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("messageId") messageId: String, @Body requestBody: EditMessageDto, ) - @DELETE("/message/remove/{messageId}") + @DELETE("message/remove/{messageId}") suspend fun deleteMessage( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("messageId") messageId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/MetadataApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/MetadataApi.kt similarity index 74% rename from data/src/main/kotlin/org/tidepool/sdk/api/MetadataApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/MetadataApi.kt index 96a5605..f99b946 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/MetadataApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/MetadataApi.kt @@ -3,28 +3,28 @@ package org.tidepool.sdk.api import kotlinx.serialization.json.JsonObject import org.tidepool.sdk.dto.metadata.UserProfileDto import org.tidepool.sdk.dto.metadata.users.TrustUserDto -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path interface MetadataApi { - @GET("/metadata/collections") + @GET("metadata/collections") suspend fun getMetadataCollections( @Header("X-Tidepool-Session-Token") sessionToken: String ): List - @GET("/metadata/{userId}/{collectionName}") + @GET("metadata/{userId}/{collectionName}") suspend fun getUserMetadataCollection( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Path("collectionName") collectionName: String ): JsonObject - @POST("/metadata/{userId}/{collectionName}") + @POST("metadata/{userId}/{collectionName}") suspend fun updateUserMetadataCollectionPost( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -32,7 +32,7 @@ interface MetadataApi { @Body collection: JsonObject ): JsonObject - @PUT("/metadata/{userId}/{collectionName}") + @PUT("metadata/{userId}/{collectionName}") suspend fun updateUserMetadataCollectionPut( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @@ -40,20 +40,20 @@ interface MetadataApi { @Body collection: JsonObject ): JsonObject - @GET("/metadata/{userId}/private/{fieldName}") + @GET("metadata/{userId}/private/{fieldName}") suspend fun getUserPrivateMetadataItem( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String, @Path("fieldName") fieldName: String ): JsonObject - @GET("/metadata/users/{userId}/users") + @GET("metadata/users/{userId}/users") suspend fun getTrustUsers( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String ): List - @GET("/metadata/{userId}/profile") + @GET("metadata/{userId}/profile") suspend fun getUserProfile( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/MetricsApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/MetricsApi.kt similarity index 71% rename from data/src/main/kotlin/org/tidepool/sdk/api/MetricsApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/MetricsApi.kt index 66a37a8..095346c 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/MetricsApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/MetricsApi.kt @@ -1,13 +1,13 @@ package org.tidepool.sdk.api -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.Path -import retrofit2.http.QueryMap +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.QueryMap interface MetricsApi { - @GET("/metrics/user/{userId}/{eventName}") + @GET("metrics/user/{userId}/{eventName}") suspend fun recordMetricsEventForUser( @Path("userId") userId: String, @Path("eventName") eventName: String, @@ -15,14 +15,14 @@ interface MetricsApi { @QueryMap parameters: Map, ) - @GET("/metrics/thisuser/{eventName}") + @GET("metrics/thisuser/{eventName}") suspend fun recordMetricsEventForLoggedInUser( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("eventName") eventName: String, @QueryMap parameters: Map, ) - @GET("/metrics/server/{serverName}/{eventName}") + @GET("metrics/server/{serverName}/{eventName}") suspend fun recordMetricsEventForServer( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("serverName") serverName: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/PrescriptionApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/PrescriptionApi.kt similarity index 77% rename from data/src/main/kotlin/org/tidepool/sdk/api/PrescriptionApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/PrescriptionApi.kt index 56ccf1a..29ae4ad 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/PrescriptionApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/PrescriptionApi.kt @@ -3,33 +3,33 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.prescription.NewPrescriptionDto import org.tidepool.sdk.dto.prescription.PrescriptionDto import org.tidepool.sdk.dto.prescription.UpdatePrescriptionDto -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import retrofit2.http.Query +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query interface PrescriptionApi { // Create a new prescription - @POST("/prescriptions") + @POST("prescriptions") suspend fun createPrescription( @Header("X-Tidepool-Session-Token") sessionToken: String, @Body requestBody: NewPrescriptionDto ): PrescriptionDto // Get prescription by ID - @GET("/prescriptions/{prescriptionId}") + @GET("prescriptions/{prescriptionId}") suspend fun getPrescription( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("prescriptionId") prescriptionId: String ): PrescriptionDto // Update prescription - @PUT("/prescriptions/{prescriptionId}") + @PUT("prescriptions/{prescriptionId}") suspend fun updatePrescription( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("prescriptionId") prescriptionId: String, @@ -37,14 +37,14 @@ interface PrescriptionApi { ): PrescriptionDto // Delete prescription - @DELETE("/prescriptions/{prescriptionId}") + @DELETE("prescriptions/{prescriptionId}") suspend fun deletePrescription( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("prescriptionId") prescriptionId: String ) // Get prescriptions for a patient - @GET("/prescriptions/patient/{patientId}") + @GET("prescriptions/patient/{patientId}") suspend fun getPrescriptionsForPatient( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("patientId") patientId: String, @@ -54,7 +54,7 @@ interface PrescriptionApi { ): List // Get prescriptions by prescriber - @GET("/prescriptions/prescriber/{prescriberId}") + @GET("prescriptions/prescriber/{prescriberId}") suspend fun getPrescriptionsByPrescriber( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("prescriberId") prescriberId: String, @@ -64,7 +64,7 @@ interface PrescriptionApi { ): List // Get prescriptions for a clinic - @GET("/prescriptions/clinic/{clinicId}") + @GET("prescriptions/clinic/{clinicId}") suspend fun getPrescriptionsForClinic( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("clinicId") clinicId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/SummaryApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/SummaryApi.kt similarity index 62% rename from data/src/main/kotlin/org/tidepool/sdk/api/SummaryApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/SummaryApi.kt index ea0f784..2a5608b 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/SummaryApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/SummaryApi.kt @@ -1,13 +1,13 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.summary.SummaryDto -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.Path +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.Path interface SummaryApi { - @GET("/v1/summaries/{summaryType}/{userId}") + @GET("v1/summaries/{summaryType}/{userId}") suspend fun getSummary( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("summaryType") summaryType: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/TaskApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/TaskApi.kt similarity index 70% rename from data/src/main/kotlin/org/tidepool/sdk/api/TaskApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/TaskApi.kt index 2bc6ffd..15f383c 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/TaskApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/TaskApi.kt @@ -3,18 +3,18 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.task.NewTaskDto import org.tidepool.sdk.dto.task.TaskDto import org.tidepool.sdk.dto.task.UpdateTaskDto -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import retrofit2.http.Query +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query interface TaskApi { - @GET("/v1/tasks") + @GET("v1/tasks") suspend fun getTasks( @Header("X-Tidepool-Session-Token") sessionToken: String, @Query("name") name: String? = null, @@ -24,26 +24,26 @@ interface TaskApi { @Query("size") size: Int? = null ): List - @POST("/v1/tasks") + @POST("v1/tasks") suspend fun createTask( @Header("X-Tidepool-Session-Token") sessionToken: String, @Body requestBody: NewTaskDto ): TaskDto - @GET("/v1/tasks/{taskId}") + @GET("v1/tasks/{taskId}") suspend fun getTask( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("taskId") taskId: String ): TaskDto - @PUT("/v1/tasks/{taskId}") + @PUT("v1/tasks/{taskId}") suspend fun updateTask( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("taskId") taskId: String, @Body requestBody: UpdateTaskDto ): TaskDto - @DELETE("/v1/tasks/{taskId}") + @DELETE("v1/tasks/{taskId}") suspend fun deleteTask( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("taskId") taskId: String diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/UserApi.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/api/UserApi.kt similarity index 66% rename from data/src/main/kotlin/org/tidepool/sdk/api/UserApi.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/api/UserApi.kt index 5522514..e6e0b32 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/api/UserApi.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/api/UserApi.kt @@ -1,18 +1,18 @@ package org.tidepool.sdk.api import org.tidepool.sdk.dto.user.UserDto -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.Path +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.Path interface UserApi { - @GET("/auth/user") + @GET("auth/user") suspend fun getCurrentUserInfo( @Header("X-Tidepool-Session-Token") sessionToken: String ): UserDto - @GET("/auth/user/{userId}") + @GET("auth/user/{userId}") suspend fun getUserInfo( @Header("X-Tidepool-Session-Token") sessionToken: String, @Path("userId") userId: String diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/BasalAutomatedDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/BasalAutomatedDataDao.kt new file mode 100644 index 0000000..4c8b19a --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/BasalAutomatedDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.BasalAutomatedDataEntity + +@Dao +interface BasalAutomatedDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: BasalAutomatedDataEntity) + + @Delete + suspend fun delete(data: BasalAutomatedDataEntity) + + @Query("SELECT * FROM basal_automated_data WHERE id = :id") + suspend fun getById(id: String): BasalAutomatedDataEntity? + + @Query("SELECT * FROM basal_automated_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/BolusDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/BolusDataDao.kt new file mode 100644 index 0000000..d8c4540 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/BolusDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.BolusDataEntity + +@Dao +interface BolusDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: BolusDataEntity) + + @Delete + suspend fun delete(data: BolusDataEntity) + + @Query("SELECT * FROM bolus_data WHERE id = :id") + suspend fun getById(id: String): BolusDataEntity? + + @Query("SELECT * FROM bolus_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/CgmSettingsDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/CgmSettingsDataDao.kt new file mode 100644 index 0000000..17ef752 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/CgmSettingsDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.CgmSettingsDataEntity + +@Dao +interface CgmSettingsDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: CgmSettingsDataEntity) + + @Delete + suspend fun delete(data: CgmSettingsDataEntity) + + @Query("SELECT * FROM cgm_settings_data WHERE id = :id") + suspend fun getById(id: String): CgmSettingsDataEntity? + + @Query("SELECT * FROM cgm_settings_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/ContinuousGlucoseDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/ContinuousGlucoseDataDao.kt new file mode 100644 index 0000000..726ebfb --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/ContinuousGlucoseDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.ContinuousGlucoseDataEntity + +@Dao +interface ContinuousGlucoseDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: ContinuousGlucoseDataEntity) + + @Delete + suspend fun delete(data: ContinuousGlucoseDataEntity) + + @Query("SELECT * FROM continuous_glucose_data WHERE id = :id") + suspend fun getById(id: String): ContinuousGlucoseDataEntity? + + @Query("SELECT * FROM continuous_glucose_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/ControllerSettingsDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/ControllerSettingsDataDao.kt new file mode 100644 index 0000000..a7f6dec --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/ControllerSettingsDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.ControllerSettingsDataEntity + +@Dao +interface ControllerSettingsDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: ControllerSettingsDataEntity) + + @Delete + suspend fun delete(data: ControllerSettingsDataEntity) + + @Query("SELECT * FROM controller_settings_data WHERE id = :id") + suspend fun getById(id: String): ControllerSettingsDataEntity? + + @Query("SELECT * FROM controller_settings_data") + suspend fun getAll(): List +} diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/DatabaseConverters.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/DatabaseConverters.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/database/DatabaseConverters.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/DatabaseConverters.kt diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/DeviceEventDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/DeviceEventDataDao.kt new file mode 100644 index 0000000..7c7d026 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/DeviceEventDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.DeviceEventDataEntity + +@Dao +interface DeviceEventDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: DeviceEventDataEntity) + + @Delete + suspend fun delete(data: DeviceEventDataEntity) + + @Query("SELECT * FROM device_event_data WHERE id = :id") + suspend fun getById(id: String): DeviceEventDataEntity? + + @Query("SELECT * FROM device_event_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/DosingDecisionDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/DosingDecisionDataDao.kt new file mode 100644 index 0000000..5128404 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/DosingDecisionDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.DosingDecisionDataEntity + +@Dao +interface DosingDecisionDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: DosingDecisionDataEntity) + + @Delete + suspend fun delete(data: DosingDecisionDataEntity) + + @Query("SELECT * FROM dosing_decision_data WHERE id = :id") + suspend fun getById(id: String): DosingDecisionDataEntity? + + @Query("SELECT * FROM dosing_decision_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/FoodDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/FoodDataDao.kt new file mode 100644 index 0000000..1fe171b --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/FoodDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.FoodDataEntity + +@Dao +interface FoodDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: FoodDataEntity) + + @Delete + suspend fun delete(data: FoodDataEntity) + + @Query("SELECT * FROM food_data WHERE id = :id") + suspend fun getById(id: String): FoodDataEntity? + + @Query("SELECT * FROM food_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/InsulinDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/InsulinDataDao.kt new file mode 100644 index 0000000..7b15647 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/InsulinDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.InsulinDataEntity + +@Dao +interface InsulinDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: InsulinDataEntity) + + @Delete + suspend fun delete(data: InsulinDataEntity) + + @Query("SELECT * FROM insulin_data WHERE id = :id") + suspend fun getById(id: String): InsulinDataEntity? + + @Query("SELECT * FROM insulin_data") + suspend fun getAll(): List +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/LoopKitDatabase.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/LoopKitDatabase.kt new file mode 100644 index 0000000..35a9198 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/LoopKitDatabase.kt @@ -0,0 +1,47 @@ +package org.tidepool.sdk.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import org.tidepool.sdk.database.entity.data.BasalAutomatedDataEntity +import org.tidepool.sdk.database.entity.data.BaseDataEntity +import org.tidepool.sdk.database.entity.data.BolusDataEntity +import org.tidepool.sdk.database.entity.data.CgmSettingsDataEntity +import org.tidepool.sdk.database.entity.data.ContinuousGlucoseDataEntity +import org.tidepool.sdk.database.entity.data.ControllerSettingsDataEntity +import org.tidepool.sdk.database.entity.data.DeviceEventDataEntity +import org.tidepool.sdk.database.entity.data.DosingDecisionDataEntity +import org.tidepool.sdk.database.entity.data.FoodDataEntity +import org.tidepool.sdk.database.entity.data.InsulinDataEntity +import org.tidepool.sdk.database.entity.data.PumpSettingsDataEntity + +@Database( + version = 1, + exportSchema = false, + entities = [ + BaseDataEntity::class, + BasalAutomatedDataEntity::class, + BolusDataEntity::class, + ContinuousGlucoseDataEntity::class, + DosingDecisionDataEntity::class, + FoodDataEntity::class, + InsulinDataEntity::class, + DeviceEventDataEntity::class, + CgmSettingsDataEntity::class, + ControllerSettingsDataEntity::class, + PumpSettingsDataEntity::class, + ], +) +@TypeConverters(DatabaseConverters::class) +abstract class LoopKitDatabase : RoomDatabase() { + abstract fun basalAutomatedDataDao(): BasalAutomatedDataDao + abstract fun bolusDataDao(): BolusDataDao + abstract fun continuousGlucoseDataDao(): ContinuousGlucoseDataDao + abstract fun dosingDecisionDataDao(): DosingDecisionDataDao + abstract fun foodDataDao(): FoodDataDao + abstract fun insulinDataDao(): InsulinDataDao + abstract fun deviceEventDataDao(): DeviceEventDataDao + abstract fun cgmSettingsDataDao(): CgmSettingsDataDao + abstract fun controllerSettingsDataDao(): ControllerSettingsDataDao + abstract fun pumpSettingsDataDao(): PumpSettingsDataDao +} \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/PumpSettingsDataDao.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/PumpSettingsDataDao.kt new file mode 100644 index 0000000..b696a14 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/PumpSettingsDataDao.kt @@ -0,0 +1,23 @@ +package org.tidepool.sdk.database + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.tidepool.sdk.database.entity.data.PumpSettingsDataEntity + +@Dao +interface PumpSettingsDataDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(data: PumpSettingsDataEntity) + + @Delete + suspend fun delete(data: PumpSettingsDataEntity) + + @Query("SELECT * FROM pump_settings_data WHERE id = :id") + suspend fun getById(id: String): PumpSettingsDataEntity? + + @Query("SELECT * FROM pump_settings_data") + suspend fun getAll(): List +} diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BasalAutomatedDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BasalAutomatedDataEntity.kt similarity index 88% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BasalAutomatedDataEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BasalAutomatedDataEntity.kt index 4ae3780..e4f4dc5 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BasalAutomatedDataEntity.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BasalAutomatedDataEntity.kt @@ -17,7 +17,7 @@ data class BasalAutomatedDataEntity( @ColumnInfo(name = "type") override var type: String, @ColumnInfo(name = "time") - override var time: Instant? = null, + override var time: Long? = null, @ColumnInfo(name = "annotations") override var annotations: String? = null, // JSON string @ColumnInfo(name = "associations") @@ -35,7 +35,7 @@ data class BasalAutomatedDataEntity( @ColumnInfo(name = "time_zone") override var timeZone: String? = null, // TimeZone ID @ColumnInfo(name = "time_zone_offset") - override var timeZoneOffset: Long? = null, // Duration in milliseconds + override var timeZoneOffset: Int? = null, // Duration In Minutes // BasalAutomatedDataDto specific fields @ColumnInfo(name = "delivery_type") @@ -66,16 +66,16 @@ data class BasalAutomatedDataEntity( fun BasalAutomatedDataDto.toEntity() = BasalAutomatedDataEntity( id = id, type = Json.encodeToString(type), - time = time, - annotations = Json.encodeToString(annotations.orEmpty()), - associations = Json.encodeToString(associations.orEmpty()), + time = time?.epochSecond, + annotations = Json.encodeToString(annotations), + associations = Json.encodeToString(associations), clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, conversionOffset = conversionOffset?.inWholeMilliseconds, dataSetId = dataSetId, deviceTime = deviceTime, - notes = Json.encodeToString(notes.orEmpty()), + notes = Json.encodeToString(notes), timeZone = timeZone?.id, - timeZoneOffset = timeZoneOffset?.inWholeMilliseconds, + timeZoneOffset = timeZoneOffset, deliveryType = Json.encodeToString(deliveryType), duration = duration, expectedDuration = expectedDuration, @@ -86,7 +86,7 @@ fun BasalAutomatedDataDto.toEntity() = BasalAutomatedDataEntity( fun BasalAutomatedDataEntity.toDto() = BasalAutomatedDataDto( id = id, type = Json.decodeFromString(type), - time = time, + time = time?.let { Instant.ofEpochSecond(it) }, annotations = if (annotations.isNullOrBlank()) emptyList() else Json.decodeFromString(annotations!!), associations = if (associations.isNullOrBlank()) emptyList() else Json.decodeFromString(associations!!), clockDriftOffset = clockDriftOffset?.milliseconds, @@ -95,7 +95,7 @@ fun BasalAutomatedDataEntity.toDto() = BasalAutomatedDataDto( deviceTime = deviceTime, notes = if (notes.isNullOrBlank()) emptyList() else Json.decodeFromString(notes!!), timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, - timeZoneOffset = timeZoneOffset?.milliseconds, + timeZoneOffset = timeZoneOffset, deliveryType = Json.decodeFromString(deliveryType), duration = duration, expectedDuration = expectedDuration, diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BaseDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BaseDataEntity.kt similarity index 57% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BaseDataEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BaseDataEntity.kt index 79240b7..0c6617f 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BaseDataEntity.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BaseDataEntity.kt @@ -9,6 +9,9 @@ import org.tidepool.sdk.dto.data.ContinuousGlucoseDataDto import org.tidepool.sdk.dto.data.DosingDecisionDataDto import org.tidepool.sdk.dto.data.FoodDataDto import org.tidepool.sdk.dto.data.InsulinDataDto +import org.tidepool.sdk.dto.data.DeviceEventDataDto +import org.tidepool.sdk.dto.data.CgmSettingsDataDto +import org.tidepool.sdk.dto.data.ControllerSettingsDataDto import org.tidepool.sdk.model.data.BaseData import org.tidepool.sdk.model.data.DataType import java.time.Instant @@ -18,7 +21,7 @@ sealed class BaseDataEntity( @PrimaryKey open var id: String, open var type: String, - open var time: Instant?, + open var time: Long?, open var annotations: String?, // JSON string open var associations: String?, // JSON string open var clockDriftOffset: Long?, // Duration in milliseconds @@ -27,25 +30,48 @@ sealed class BaseDataEntity( open var deviceTime: String?, open var notes: String?, // JSON string open var timeZone: String?, // TimeZone ID - open var timeZoneOffset: Long?, // Duration in milliseconds + open var timeZoneOffset: Int?, // Duration in minutes ) internal fun BaseDataEntity.toDomain(): BaseData = when (this) { - is BasalAutomatedDataEntity -> toDomain() - is BolusDataEntity -> toDomain() - is ContinuousGlucoseDataEntity -> toDomain() - is DosingDecisionDataEntity -> toDomain() - is FoodDataEntity -> toDomain() - is InsulinDataEntity -> toDomain() + is BasalAutomatedDataEntity -> toDomain() + is BolusDataEntity -> toDomain() + is ContinuousGlucoseDataEntity -> toDomain() + is DosingDecisionDataEntity -> toDomain() + is CgmSettingsDataEntity -> toDomain() + is ControllerSettingsDataEntity -> toDomain() + is FoodDataEntity -> toDomain() + is InsulinDataEntity -> toDomain() + is DeviceEventDataEntity -> toDomain() + is PumpSettingsDataEntity -> toDomain() } internal fun BaseDataEntity.toDto(): BaseDataDto = when (this) { - is BasalAutomatedDataEntity -> toDto() - is BolusDataEntity -> toDto() - is ContinuousGlucoseDataEntity -> toDto() - is DosingDecisionDataEntity -> toDto() - is FoodDataEntity -> toDto() - is InsulinDataEntity -> toDto() + is BasalAutomatedDataEntity -> toDto() + is BolusDataEntity -> toDto() + is ContinuousGlucoseDataEntity -> toDto() + is DosingDecisionDataEntity -> toDto() + is CgmSettingsDataEntity -> toDto() + is ControllerSettingsDataEntity -> toDto() + is FoodDataEntity -> toDto() + is InsulinDataEntity -> toDto() + is DeviceEventDataEntity -> toDto() + is PumpSettingsDataEntity -> toDto() +} + +fun BaseDataDto.toEntity(): BaseDataEntity = when (this) { + is BasalAutomatedDataDto -> toEntity() + is BolusDataDto -> toEntity() + is ContinuousGlucoseDataDto -> toEntity() + is DosingDecisionDataDto -> toEntity() + is CgmSettingsDataDto -> toEntity() + is ControllerSettingsDataDto -> toEntity() + is FoodDataDto -> toEntity() + is InsulinDataDto -> toEntity() + is DeviceEventDataDto -> toEntity() + else -> throw IllegalArgumentException( + "Unknown BaseDataDto subtype: ${this::class}" + ) } internal fun DataType.toEntity(): DataTypeEntity = when (this) { @@ -67,14 +93,4 @@ internal fun DataType.toEntity(): DataTypeEntity = when (this) { DataType.PumpStatus -> DataTypeEntity.PumpStatus DataType.ReportedState -> DataTypeEntity.ReportedState DataType.Smbg -> DataTypeEntity.Smbg -} - -fun BaseDataDto.toEntity(): BaseDataEntity = when (this) { - is BasalAutomatedDataDto -> toEntity() - is BolusDataDto -> toEntity() - is ContinuousGlucoseDataDto -> toEntity() - is DosingDecisionDataDto -> toEntity() - is FoodDataDto -> toEntity() - is InsulinDataDto -> toEntity() - else -> throw IllegalArgumentException("Unknown BaseDataDto subtype: ${this::class}") } \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BolusDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BolusDataEntity.kt similarity index 87% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BolusDataEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BolusDataEntity.kt index 7a54320..ee7ff63 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/BolusDataEntity.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/BolusDataEntity.kt @@ -18,7 +18,7 @@ data class BolusDataEntity( @ColumnInfo(name = "type") override var type: String, @ColumnInfo(name = "time") - override var time: Instant? = null, + override var time: Long? = null, @ColumnInfo(name = "annotations") override var annotations: String? = null, // JSON string @ColumnInfo(name = "associations") @@ -36,8 +36,8 @@ data class BolusDataEntity( @ColumnInfo(name = "time_zone") override var timeZone: String? = null, // TimeZone ID @ColumnInfo(name = "time_zone_offset") - override var timeZoneOffset: Long? = null, // Duration in milliseconds - + override var timeZoneOffset: Int?, // Duration in minutes + @ColumnInfo(name = "sub_type") var subType: String = "normal", @ColumnInfo(name = "delivery_context") @@ -60,16 +60,16 @@ data class BolusDataEntity( fun BolusDataDto.toEntity() = BolusDataEntity( id = id, type = Json.encodeToString(type), - time = time, - annotations = annotations.let { Json.encodeToString(it) }, - associations = associations.let { Json.encodeToString(it) }, + time = time?.epochSecond, + annotations = Json.encodeToString(annotations), + associations = Json.encodeToString(associations), clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, conversionOffset = conversionOffset?.inWholeMilliseconds, dataSetId = dataSetId, deviceTime = deviceTime, - notes = notes.let { Json.encodeToString(it) }, + notes = Json.encodeToString(notes), timeZone = timeZone?.id, - timeZoneOffset = timeZoneOffset?.inWholeMilliseconds, + timeZoneOffset = timeZoneOffset, subType = Json.encodeToString(subType), deliveryContext = Json.encodeToString(deliveryContext), ) @@ -77,7 +77,7 @@ fun BolusDataDto.toEntity() = BolusDataEntity( fun BolusDataEntity.toDto() = BolusDataDto( id = id, type = Json.decodeFromString(type), - time = time, + time = time?.let { Instant.ofEpochSecond(it) }, annotations = annotations ?.let { Json.decodeFromString>>(it) } .orEmpty(), @@ -92,7 +92,7 @@ fun BolusDataEntity.toDto() = BolusDataDto( ?.let { Json.decodeFromString>(it) } .orEmpty(), timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, - timeZoneOffset = timeZoneOffset?.milliseconds, + timeZoneOffset = timeZoneOffset, subType = Json.decodeFromString(subType), deliveryContext = Json.decodeFromString(deliveryContext), ) diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/CgmSettingsDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/CgmSettingsDataEntity.kt new file mode 100644 index 0000000..ee95d49 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/CgmSettingsDataEntity.kt @@ -0,0 +1,89 @@ +package org.tidepool.sdk.database.entity.data + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import kotlinx.serialization.json.Json +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.data.CgmSettingsDataDto +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration.Companion.milliseconds + +@Entity(tableName = "cgm_settings_data") +data class CgmSettingsDataEntity( + @PrimaryKey + @ColumnInfo(name = "id") + override var id: String, + @ColumnInfo(name = "type") + override var type: String, + @ColumnInfo(name = "time") + override var time: Long? = null, + @ColumnInfo(name = "annotations") + override var annotations: String? = null, // JSON string + @ColumnInfo(name = "associations") + override var associations: String? = null, // JSON string + @ColumnInfo(name = "clock_drift_offset") + override var clockDriftOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "conversion_offset") + override var conversionOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "data_set_id") + override var dataSetId: String? = null, + @ColumnInfo(name = "device_time") + override var deviceTime: String? = null, + @ColumnInfo(name = "notes") + override var notes: String? = null, // JSON string + @ColumnInfo(name = "time_zone") + override var timeZone: String? = null, // TimeZone ID + @ColumnInfo(name = "time_zone_offset") + override var timeZoneOffset: Int?, // Duration in minutes +) : BaseDataEntity( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) + +fun CgmSettingsDataDto.toEntity() = CgmSettingsDataEntity( + id = id, + type = Json.encodeToString(type), + time = time?.epochSecond, + annotations = annotations.let { Json.encodeToString(it) }, + associations = associations.let { Json.encodeToString(it) }, + clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, + conversionOffset = conversionOffset?.inWholeMilliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes.let { Json.encodeToString(it) }, + timeZone = timeZone?.id, + timeZoneOffset = timeZoneOffset, +) + +fun CgmSettingsDataEntity.toDto() = CgmSettingsDataDto( + id = id, + type = Json.decodeFromString(type), + time = time?.let { Instant.ofEpochSecond(it) }, + annotations = annotations + ?.let { Json.decodeFromString>>(it) } + .orEmpty(), + associations = associations + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + clockDriftOffset = clockDriftOffset?.milliseconds, + conversionOffset = conversionOffset?.milliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, + timeZoneOffset = timeZoneOffset, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/ContinuousGlucoseDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/ContinuousGlucoseDataEntity.kt similarity index 93% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/ContinuousGlucoseDataEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/ContinuousGlucoseDataEntity.kt index 51478ca..e55a8d3 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/ContinuousGlucoseDataEntity.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/ContinuousGlucoseDataEntity.kt @@ -18,7 +18,7 @@ data class ContinuousGlucoseDataEntity( @ColumnInfo(name = "type") override var type: String, @ColumnInfo(name = "time") - override var time: Instant? = null, + override var time: Long? = null, @ColumnInfo(name = "annotations") override var annotations: String? = null, // JSON string @ColumnInfo(name = "associations") @@ -36,7 +36,7 @@ data class ContinuousGlucoseDataEntity( @ColumnInfo(name = "time_zone") override var timeZone: String? = null, // TimeZone ID @ColumnInfo(name = "time_zone_offset") - override var timeZoneOffset: Long? = null, // Duration in milliseconds + override var timeZoneOffset: Int?, // Duration in minutes @ColumnInfo(name = "value") var value: Double? = null, @@ -64,7 +64,7 @@ data class ContinuousGlucoseDataEntity( fun ContinuousGlucoseDataDto.toEntity() = ContinuousGlucoseDataEntity( id = id, type = Json.encodeToString(type), - time = time, + time = time?.epochSecond, annotations = annotations.let { Json.encodeToString(it) }, associations = associations.let { Json.encodeToString(it) }, clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, @@ -73,7 +73,7 @@ fun ContinuousGlucoseDataDto.toEntity() = ContinuousGlucoseDataEntity( deviceTime = deviceTime, notes = notes.let { Json.encodeToString(it) }, timeZone = timeZone?.id, - timeZoneOffset = timeZoneOffset?.inWholeMilliseconds, + timeZoneOffset = timeZoneOffset, value = value, units = units?.let { Json.encodeToString(it) }, trend = trend?.let { Json.encodeToString(it) }, @@ -83,7 +83,7 @@ fun ContinuousGlucoseDataDto.toEntity() = ContinuousGlucoseDataEntity( fun ContinuousGlucoseDataEntity.toDto() = ContinuousGlucoseDataDto( id = id, type = Json.decodeFromString(type), - time = time, + time = time?.let { Instant.ofEpochSecond(it) }, annotations = annotations ?.let { Json.decodeFromString>>(it) } .orEmpty(), @@ -98,7 +98,7 @@ fun ContinuousGlucoseDataEntity.toDto() = ContinuousGlucoseDataDto( ?.let { Json.decodeFromString>(it) } .orEmpty(), timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, - timeZoneOffset = timeZoneOffset?.milliseconds, + timeZoneOffset = timeZoneOffset, value = value, units = units?.let { Json.decodeFromString(it) }, trend = trend?.let { Json.decodeFromString(it) }, diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/ControllerSettingsDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/ControllerSettingsDataEntity.kt new file mode 100644 index 0000000..15dd49b --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/ControllerSettingsDataEntity.kt @@ -0,0 +1,89 @@ +package org.tidepool.sdk.database.entity.data + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import kotlinx.serialization.json.Json +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.data.ControllerSettingsDataDto +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration.Companion.milliseconds + +@Entity(tableName = "controller_settings_data") +data class ControllerSettingsDataEntity( + @PrimaryKey + @ColumnInfo(name = "id") + override var id: String, + @ColumnInfo(name = "type") + override var type: String, + @ColumnInfo(name = "time") + override var time: Long? = null, + @ColumnInfo(name = "annotations") + override var annotations: String? = null, // JSON string + @ColumnInfo(name = "associations") + override var associations: String? = null, // JSON string + @ColumnInfo(name = "clock_drift_offset") + override var clockDriftOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "conversion_offset") + override var conversionOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "data_set_id") + override var dataSetId: String? = null, + @ColumnInfo(name = "device_time") + override var deviceTime: String? = null, + @ColumnInfo(name = "notes") + override var notes: String? = null, // JSON string + @ColumnInfo(name = "time_zone") + override var timeZone: String? = null, // TimeZone ID + @ColumnInfo(name = "time_zone_offset") + override var timeZoneOffset: Int?, // Duration in minutes +) : BaseDataEntity( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) + +fun ControllerSettingsDataDto.toEntity() = ControllerSettingsDataEntity( + id = id, + type = Json.encodeToString(type), + time = time?.epochSecond, + annotations = annotations.let { Json.encodeToString(it) }, + associations = associations.let { Json.encodeToString(it) }, + clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, + conversionOffset = conversionOffset?.inWholeMilliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes.let { Json.encodeToString(it) }, + timeZone = timeZone?.id, + timeZoneOffset = timeZoneOffset, +) + +fun ControllerSettingsDataEntity.toDto() = ControllerSettingsDataDto( + id = id, + type = Json.decodeFromString(type), + time = time?.let { Instant.ofEpochSecond(it) }, + annotations = annotations + ?.let { Json.decodeFromString>>(it) } + .orEmpty(), + associations = associations + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + clockDriftOffset = clockDriftOffset?.milliseconds, + conversionOffset = conversionOffset?.milliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, + timeZoneOffset = timeZoneOffset, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/DataTypeEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DataTypeEntity.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/DataTypeEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DataTypeEntity.kt diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DeviceEventDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DeviceEventDataEntity.kt new file mode 100644 index 0000000..d5dd55f --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DeviceEventDataEntity.kt @@ -0,0 +1,110 @@ +package org.tidepool.sdk.database.entity.data + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import kotlinx.serialization.json.Json +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.data.DeviceEventDataDto +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration.Companion.milliseconds + +@Entity(tableName = "device_event_data") +data class DeviceEventDataEntity( + @PrimaryKey + @ColumnInfo(name = "id") + override var id: String, + @ColumnInfo(name = "type") + override var type: String, + @ColumnInfo(name = "time") + override var time: Long? = null, + @ColumnInfo(name = "annotations") + override var annotations: String? = null, // JSON string + @ColumnInfo(name = "associations") + override var associations: String? = null, // JSON string + @ColumnInfo(name = "clock_drift_offset") + override var clockDriftOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "conversion_offset") + override var conversionOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "data_set_id") + override var dataSetId: String? = null, + @ColumnInfo(name = "device_time") + override var deviceTime: String? = null, + @ColumnInfo(name = "notes") + override var notes: String? = null, // JSON string + @ColumnInfo(name = "time_zone") + override var timeZone: String? = null, // TimeZone ID + @ColumnInfo(name = "time_zone_offset") + override var timeZoneOffset: Int?, // Duration in minutes + + @ColumnInfo(name = "sub_type") + var subType: String, + @ColumnInfo(name = "device_identifier") + var deviceIdentifier: String? = null, + @ColumnInfo(name = "expected_lifetime_seconds") + var expectedLifetimeSeconds: Double? = null, + @ColumnInfo(name = "warmup_period_seconds") + var warmupPeriodSeconds: Double? = null, + @ColumnInfo(name = "failure_message") + var failureMessage: String? = null, +) : BaseDataEntity( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) + +fun DeviceEventDataDto.toEntity() = DeviceEventDataEntity( + id = id, + type = Json.encodeToString(type), + time = time?.epochSecond, + annotations = annotations.let { Json.encodeToString(it) }, + associations = associations.let { Json.encodeToString(it) }, + clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, + conversionOffset = conversionOffset?.inWholeMilliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes.let { Json.encodeToString(it) }, + timeZone = timeZone?.id, + timeZoneOffset = timeZoneOffset, + subType = Json.encodeToString(subType), + deviceIdentifier = deviceIdentifier, + expectedLifetimeSeconds = expectedLifetimeSeconds, + warmupPeriodSeconds = warmupPeriodSeconds, + failureMessage = failureMessage, +) + +fun DeviceEventDataEntity.toDto() = DeviceEventDataDto( + id = id, + type = Json.decodeFromString(type), + time = time?.let { Instant.ofEpochSecond(it) }, + annotations = annotations + ?.let { Json.decodeFromString>>(it) } + .orEmpty(), + associations = associations + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + clockDriftOffset = clockDriftOffset?.milliseconds, + conversionOffset = conversionOffset?.milliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, + timeZoneOffset = timeZoneOffset, + subType = Json.decodeFromString(subType), + deviceIdentifier = deviceIdentifier, + expectedLifetimeSeconds = expectedLifetimeSeconds, + warmupPeriodSeconds = warmupPeriodSeconds, + failureMessage = failureMessage, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/DosingDecisionDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DosingDecisionDataEntity.kt similarity index 65% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/DosingDecisionDataEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DosingDecisionDataEntity.kt index 65bb0a7..960b19d 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/DosingDecisionDataEntity.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/DosingDecisionDataEntity.kt @@ -4,6 +4,9 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule +import org.tidepool.sdk.deserialization.InstantSerializer +import org.tidepool.sdk.deserialization.TimeZoneSerializer import org.tidepool.sdk.dto.AssociationDto import org.tidepool.sdk.dto.data.DosingDecisionDataDto import java.time.Instant @@ -18,7 +21,7 @@ data class DosingDecisionDataEntity( @ColumnInfo(name = "type") override var type: String, @ColumnInfo(name = "time") - override var time: Instant? = null, + override var time: Long? = null, @ColumnInfo(name = "annotations") override var annotations: String? = null, // JSON string @ColumnInfo(name = "associations") @@ -36,8 +39,8 @@ data class DosingDecisionDataEntity( @ColumnInfo(name = "time_zone") override var timeZone: String? = null, // TimeZone ID @ColumnInfo(name = "time_zone_offset") - override var timeZoneOffset: Long? = null, // Duration in milliseconds - + override var timeZoneOffset: Int?, // Duration in minutes + @ColumnInfo(name = "reason") var reason: String = "", @ColumnInfo(name = "carbs_on_board") @@ -69,33 +72,49 @@ data class DosingDecisionDataEntity( timeZoneOffset = timeZoneOffset, ) -fun DosingDecisionDataDto.toEntity() = DosingDecisionDataEntity( - id = id, - type = Json.encodeToString(type), - time = time, - annotations = annotations.let { Json.encodeToString(it) }, - associations = associations.let { Json.encodeToString(it) }, - clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, - conversionOffset = conversionOffset?.inWholeMilliseconds, - dataSetId = dataSetId, - deviceTime = deviceTime, - notes = notes.let { Json.encodeToString(it) }, - timeZone = timeZone?.id, - timeZoneOffset = timeZoneOffset?.inWholeMilliseconds, - reason = reason, - carbsOnBoard = carbsOnBoard?.let { Json.encodeToString(it) }, - insulinOnBoard = insulinOnBoard?.let { Json.encodeToString(it) }, - recommendedBasal = recommendedBasal?.let { Json.encodeToString(it) }, - recommendedBolus = recommendedBolus?.let { Json.encodeToString(it) }, - requestedBolus = requestedBolus?.let { Json.encodeToString(it) }, - scheduleTimeZoneOffset = scheduleTimeZoneOffset, - units = Json.encodeToString(units), -) +fun DosingDecisionDataDto.toEntity(): DosingDecisionDataEntity { + val json = Json { + ignoreUnknownKeys = true + encodeDefaults = true + isLenient = true + explicitNulls = false + classDiscriminator = + "__type" // Use different discriminator to avoid conflict with 'type' property + serializersModule = SerializersModule { + contextual(Instant::class, InstantSerializer) + contextual(TimeZone::class, TimeZoneSerializer) + // Configure BaseData polymorphism + } + } + + return DosingDecisionDataEntity( + id = id, + type = json.encodeToString(type), + time = time?.epochSecond, + annotations = annotations.let { json.encodeToString(it) }, + associations = associations.let { json.encodeToString(it) }, + clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, + conversionOffset = conversionOffset?.inWholeMilliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes.let { json.encodeToString(it) }, + timeZone = timeZone?.id, + timeZoneOffset = timeZoneOffset, + reason = reason, + carbsOnBoard = carbsOnBoard?.let { json.encodeToString(it) }, + insulinOnBoard = insulinOnBoard?.let { json.encodeToString(it) }, + recommendedBasal = recommendedBasal?.let { Json.encodeToString(it) }, + recommendedBolus = recommendedBolus?.let { json.encodeToString(it) }, + requestedBolus = requestedBolus?.let { json.encodeToString(it) }, + scheduleTimeZoneOffset = scheduleTimeZoneOffset, + units = json.encodeToString(units), + ) +} fun DosingDecisionDataEntity.toDto() = DosingDecisionDataDto( id = id, type = Json.decodeFromString(type), - time = time, + time = time?.let { Instant.ofEpochSecond(it) }, annotations = annotations ?.let { Json.decodeFromString>>(it) } .orEmpty(), @@ -110,7 +129,7 @@ fun DosingDecisionDataEntity.toDto() = DosingDecisionDataDto( ?.let { Json.decodeFromString>(it) } .orEmpty(), timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, - timeZoneOffset = timeZoneOffset?.milliseconds, + timeZoneOffset = timeZoneOffset, reason = reason, carbsOnBoard = carbsOnBoard?.let { Json.decodeFromString(it) }, insulinOnBoard = insulinOnBoard?.let { Json.decodeFromString(it) }, diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/FoodDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/FoodDataEntity.kt similarity index 94% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/FoodDataEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/FoodDataEntity.kt index a4a6faa..793c2a9 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/FoodDataEntity.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/FoodDataEntity.kt @@ -18,7 +18,7 @@ data class FoodDataEntity( @ColumnInfo(name = "type") override var type: String, @ColumnInfo(name = "time") - override var time: Instant? = null, + override var time: Long? = null, @ColumnInfo(name = "annotations") override var annotations: String? = null, // JSON string @ColumnInfo(name = "associations") @@ -36,7 +36,7 @@ data class FoodDataEntity( @ColumnInfo(name = "time_zone") override var timeZone: String? = null, // TimeZone ID @ColumnInfo(name = "time_zone_offset") - override var timeZoneOffset: Long? = null, // Duration in milliseconds + override var timeZoneOffset: Int?, // Duration in minutes @ColumnInfo(name = "brand") var brand: String? = null, @@ -66,7 +66,7 @@ data class FoodDataEntity( fun FoodDataDto.toEntity() = FoodDataEntity( id = id, type = Json.encodeToString(type), - time = time, + time = time?.epochSecond, annotations = annotations.let { Json.encodeToString(it) }, associations = associations.let { Json.encodeToString(it) }, clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, @@ -75,7 +75,7 @@ fun FoodDataDto.toEntity() = FoodDataEntity( deviceTime = deviceTime, notes = notes.let { Json.encodeToString(it) }, timeZone = timeZone?.id, - timeZoneOffset = timeZoneOffset?.inWholeMilliseconds, + timeZoneOffset = timeZoneOffset, brand = brand, code = code, meal = meal?.let { meal -> @@ -94,7 +94,7 @@ fun FoodDataDto.toEntity() = FoodDataEntity( fun FoodDataEntity.toDto() = FoodDataDto( id = id, type = Json.decodeFromString(type), - time = time, + time = time?.let { Instant.ofEpochSecond(it) }, annotations = annotations ?.let { Json.decodeFromString>>(it) } .orEmpty(), @@ -109,7 +109,7 @@ fun FoodDataEntity.toDto() = FoodDataDto( ?.let { Json.decodeFromString>(it) } .orEmpty(), timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, - timeZoneOffset = timeZoneOffset?.milliseconds, + timeZoneOffset = timeZoneOffset, brand = brand, code = code, meal = meal?.let { mealString -> diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/InsulinDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/InsulinDataEntity.kt similarity index 92% rename from data/src/main/kotlin/org/tidepool/sdk/database/entity/data/InsulinDataEntity.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/InsulinDataEntity.kt index 6c2aa20..f1737a9 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/database/entity/data/InsulinDataEntity.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/InsulinDataEntity.kt @@ -18,7 +18,7 @@ data class InsulinDataEntity( @ColumnInfo(name = "type") override var type: String, @ColumnInfo(name = "time") - override var time: Instant? = null, + override var time: Long? = null, @ColumnInfo(name = "annotations") override var annotations: String? = null, // JSON string @ColumnInfo(name = "associations") @@ -36,7 +36,7 @@ data class InsulinDataEntity( @ColumnInfo(name = "time_zone") override var timeZone: String? = null, // TimeZone ID @ColumnInfo(name = "time_zone_offset") - override var timeZoneOffset: Long? = null, // Duration in milliseconds + override var timeZoneOffset: Int?, // Duration in minutes // InsulinDataDto specific fields @ColumnInfo(name = "dose") @@ -61,7 +61,7 @@ data class InsulinDataEntity( fun InsulinDataDto.toEntity() = InsulinDataEntity( id = id, type = Json.encodeToString(type), - time = time, + time = time?.epochSecond, annotations = annotations.let { Json.encodeToString(it) }, associations = associations.let { Json.encodeToString(it) }, clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, @@ -70,7 +70,7 @@ fun InsulinDataDto.toEntity() = InsulinDataEntity( deviceTime = deviceTime, notes = notes.let { Json.encodeToString(it) }, timeZone = timeZone?.id, - timeZoneOffset = timeZoneOffset?.inWholeMilliseconds, + timeZoneOffset = timeZoneOffset, dose = Json.encodeToString(dose), site = site ) @@ -78,7 +78,7 @@ fun InsulinDataDto.toEntity() = InsulinDataEntity( fun InsulinDataEntity.toDto() = InsulinDataDto( id = id, type = Json.decodeFromString(type), - time = time, + time = time?.let { Instant.ofEpochSecond(it) }, annotations = annotations ?.let { Json.decodeFromString>>(it) } .orEmpty(), @@ -93,7 +93,7 @@ fun InsulinDataEntity.toDto() = InsulinDataDto( ?.let { Json.decodeFromString>(it) } .orEmpty(), timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, - timeZoneOffset = timeZoneOffset?.milliseconds, + timeZoneOffset = timeZoneOffset, dose = Json.decodeFromString(dose), site = site ) diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/PumpSettingsDataEntity.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/PumpSettingsDataEntity.kt new file mode 100644 index 0000000..0bfe636 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/database/entity/data/PumpSettingsDataEntity.kt @@ -0,0 +1,90 @@ +package org.tidepool.sdk.database.entity.data + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import kotlinx.serialization.json.Json +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.data.PumpSettingsDataDto +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration.Companion.milliseconds + + +@Entity(tableName = "pump_settings_data") +data class PumpSettingsDataEntity( + @PrimaryKey + @ColumnInfo(name = "id") + override var id: String, + @ColumnInfo(name = "type") + override var type: String, + @ColumnInfo(name = "time") + override var time: Long? = null, + @ColumnInfo(name = "annotations") + override var annotations: String? = null, // JSON string + @ColumnInfo(name = "associations") + override var associations: String? = null, // JSON string + @ColumnInfo(name = "clock_drift_offset") + override var clockDriftOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "conversion_offset") + override var conversionOffset: Long? = null, // Duration in milliseconds + @ColumnInfo(name = "data_set_id") + override var dataSetId: String? = null, + @ColumnInfo(name = "device_time") + override var deviceTime: String? = null, + @ColumnInfo(name = "notes") + override var notes: String? = null, // JSON string + @ColumnInfo(name = "time_zone") + override var timeZone: String? = null, // TimeZone ID + @ColumnInfo(name = "time_zone_offset") + override var timeZoneOffset: Int?, +) : BaseDataEntity( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) + +fun PumpSettingsDataDto.toEntity() = PumpSettingsDataEntity( + id = id, + type = Json.encodeToString(type), + time = time?.epochSecond, + annotations = annotations.let { Json.encodeToString(it) }, + associations = associations.let { Json.encodeToString(it) }, + clockDriftOffset = clockDriftOffset?.inWholeMilliseconds, + conversionOffset = conversionOffset?.inWholeMilliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes.let { Json.encodeToString(it) }, + timeZone = timeZone?.id, + timeZoneOffset = timeZoneOffset, +) + +fun PumpSettingsDataEntity.toDto() = PumpSettingsDataDto( + id = id, + type = Json.decodeFromString(type), + time = time?.let { Instant.ofEpochSecond(it) }, + annotations = annotations + ?.let { Json.decodeFromString>>(it) } + .orEmpty(), + associations = associations + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + clockDriftOffset = clockDriftOffset?.milliseconds, + conversionOffset = conversionOffset?.milliseconds, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes + ?.let { Json.decodeFromString>(it) } + .orEmpty(), + timeZone = timeZone?.let { TimeZone.getTimeZone(it) }, + timeZoneOffset = timeZoneOffset, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/deserialization/InstantSerializer.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/InstantSerializer.kt similarity index 86% rename from data/src/main/kotlin/org/tidepool/sdk/deserialization/InstantSerializer.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/InstantSerializer.kt index 0918544..95d299f 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/deserialization/InstantSerializer.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/InstantSerializer.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import java.time.Instant +import java.time.format.DateTimeFormatter object InstantSerializer : KSerializer { @@ -14,7 +15,7 @@ object InstantSerializer : KSerializer { PrimitiveSerialDescriptor("Instant", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: Instant) { - encoder.encodeString(value.toString()) + encoder.encodeString(DateTimeFormatter.ISO_INSTANT.format(value)) } override fun deserialize(decoder: Decoder): Instant { diff --git a/data/src/main/kotlin/org/tidepool/sdk/deserialization/ResultType.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/ResultType.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/deserialization/ResultType.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/ResultType.kt diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/TimeZoneSerializer.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/TimeZoneSerializer.kt new file mode 100644 index 0000000..195c8a6 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/deserialization/TimeZoneSerializer.kt @@ -0,0 +1,24 @@ +package org.tidepool.sdk.deserialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.util.TimeZone + +object TimeZoneSerializer : KSerializer { + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("TimeZone", PrimitiveKind.STRING) + + override fun serialize( + encoder: Encoder, + value: TimeZone, + ) { + encoder.encodeString(value.id) + } + + override fun deserialize(decoder: Decoder): TimeZone = + TimeZone.getTimeZone(decoder.decodeString()) +} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/di/DataModule.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/di/DataModule.kt similarity index 51% rename from data/src/main/kotlin/org/tidepool/sdk/di/DataModule.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/di/DataModule.kt index 43eba94..cb14d17 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/di/DataModule.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/di/DataModule.kt @@ -1,17 +1,11 @@ package org.tidepool.sdk.di -import androidx.room.Room -import androidx.sqlite.driver.bundled.BundledSQLiteDriver -import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor +import org.koin.core.module.Module import org.koin.core.module.dsl.singleOf -import org.koin.core.qualifier.named import org.koin.dsl.bind import org.koin.dsl.module import org.tidepool.sdk.Environment @@ -22,7 +16,6 @@ import org.tidepool.sdk.api.BlobApi import org.tidepool.sdk.api.ClinicApi import org.tidepool.sdk.api.ConfirmationApi import org.tidepool.sdk.api.DataApi -import org.tidepool.sdk.api.ExportApi import org.tidepool.sdk.api.GeneralApi import org.tidepool.sdk.api.MessageApi import org.tidepool.sdk.api.MetadataApi @@ -31,9 +24,19 @@ import org.tidepool.sdk.api.PrescriptionApi import org.tidepool.sdk.api.SummaryApi import org.tidepool.sdk.api.TaskApi import org.tidepool.sdk.api.UserApi -import org.tidepool.sdk.database.DataDao +import org.tidepool.sdk.database.BasalAutomatedDataDao +import org.tidepool.sdk.database.BolusDataDao +import org.tidepool.sdk.database.CgmSettingsDataDao +import org.tidepool.sdk.database.ControllerSettingsDataDao +import org.tidepool.sdk.database.ContinuousGlucoseDataDao +import org.tidepool.sdk.database.DeviceEventDataDao +import org.tidepool.sdk.database.DosingDecisionDataDao +import org.tidepool.sdk.database.FoodDataDao +import org.tidepool.sdk.database.InsulinDataDao import org.tidepool.sdk.database.LoopKitDatabase +import org.tidepool.sdk.database.PumpSettingsDataDao import org.tidepool.sdk.deserialization.InstantSerializer +import org.tidepool.sdk.deserialization.TimeZoneSerializer import org.tidepool.sdk.dto.data.BasalAutomatedDataDto import org.tidepool.sdk.dto.data.BaseDataDto import org.tidepool.sdk.dto.data.BolusDataDto @@ -76,12 +79,44 @@ import org.tidepool.sdk.repository.TaskRepositoryImpl import org.tidepool.sdk.repository.UserRepositoryImpl import org.tidepool.sdk.repository.AuthorizationRepositoryImpl import org.tidepool.sdk.toInternal -import retrofit2.Retrofit import java.time.Instant +import io.ktor.client.HttpClient +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.defaultRequest +import io.ktor.serialization.kotlinx.json.json +import io.ktor.http.ContentType +import io.ktor.http.contentType +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logging +import io.ktor.client.plugins.logging.Logger +import de.jensklingenberg.ktorfit.Ktorfit +import io.ktor.client.plugins.HttpCallValidator +import io.ktor.client.plugins.ResponseException +import io.ktor.client.statement.HttpResponse +import io.ktor.client.statement.bodyAsText +import java.util.TimeZone + +expect val platformDataModule: Module + +expect fun provideAlertApi(ktorfit: Ktorfit): AlertApi +expect fun provideAuthorizationApi(ktorfit: Ktorfit): AuthorizationApi +expect fun provideBlobApi(ktorfit: Ktorfit): BlobApi +expect fun provideClinicApi(ktorfit: Ktorfit): ClinicApi +expect fun provideConfirmationApi(ktorfit: Ktorfit): ConfirmationApi +expect fun provideDataApi(ktorfit: Ktorfit): DataApi +//expect fun provideExportApi(ktorfit: Ktorfit): ExportApi +expect fun provideGeneralApi(ktorfit: Ktorfit): GeneralApi +expect fun provideMessageApi(ktorfit: Ktorfit): MessageApi +expect fun provideMetadataApi(ktorfit: Ktorfit): MetadataApi +expect fun provideMetricsApi(ktorfit: Ktorfit): MetricsApi +expect fun providePrescriptionApi(ktorfit: Ktorfit): PrescriptionApi +expect fun provideSummaryApi(ktorfit: Ktorfit): SummaryApi +expect fun provideTaskApi(ktorfit: Ktorfit): TaskApi +expect fun provideUserApi(ktorfit: Ktorfit): UserApi public val dataModule = module { - // Session Manager // JSON Configuration single { Json { @@ -89,11 +124,13 @@ public val dataModule = module { encodeDefaults = true isLenient = true explicitNulls = false + coerceInputValues = true classDiscriminator = "__type" // Use different discriminator to avoid conflict with 'type' property serializersModule = SerializersModule { contextual(Instant::class, InstantSerializer) - // Configure BaseData polymorphism + contextual(TimeZone::class, TimeZoneSerializer) + // Configure BaseData polymorphism polymorphic(BaseDataDto::class) { subclass(BasalAutomatedDataDto::class) subclass(BolusDataDto::class) @@ -112,63 +149,83 @@ public val dataModule = module { } } } - - single { - Room.databaseBuilder("loop-kit-database") - .setDriver(BundledSQLiteDriver()) - .build() - } - + + // Ktor HttpClient Configuration single { - OkHttpClient.Builder() - .addInterceptor( - HttpLoggingInterceptor() - .apply { setLevel(HttpLoggingInterceptor.Level.BODY) } - ) - .build() + HttpClient { + expectSuccess = false // Handle non-2xx responses manually + + install(ContentNegotiation) { + json(get()) + } + + install(HttpCallValidator) { + validateResponse { response: HttpResponse -> + if (response.status.value !in 200..299) { + throw ResponseException( + response = response, + cachedResponseText = response.bodyAsText(), + ) + } + } + } + + install(HttpTimeout) { + requestTimeoutMillis = 30_000 + connectTimeoutMillis = 10_000 + socketTimeoutMillis = 30_000 + } + + install(Logging) { + logger = get() + level = LogLevel.ALL + } + + defaultRequest { + headers.append("Content-Type", "application/json") + contentType(ContentType.Application.Json) + } + } } - - // TODO: Retrofit configuration will need Environment class or base URL configuration - // Main API Retrofit instance - single(qualifier = named("main")) { + + // Main API Ktorfit instance + single { val environment: EnvironmentInternal = get().toInternal() - val json: Json = get() - - Retrofit.Builder() + val httpClient: HttpClient = get() + + Ktorfit.Builder() .baseUrl(environment.url) - .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) - .client(get()) + .httpClient(httpClient) .build() } - - // Auth API Retrofit instance - single(qualifier = named("auth")) { - val environment: EnvironmentInternal = get().toInternal() - val json: Json = get() - Retrofit.Builder() - .baseUrl(environment.auth.url) - .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) - .client(get()) - .build() - } - - single { get(qualifier = named("main")).create(AlertApi::class.java) } - single { get(qualifier = named("main")).create(AuthorizationApi::class.java) } - single { get(qualifier = named("main")).create(BlobApi::class.java) } - single { get(qualifier = named("main")).create(ClinicApi::class.java) } - single { get(qualifier = named("main")).create(ConfirmationApi::class.java) } - single { get(qualifier = named("main")).create(DataApi::class.java) } - single { get(qualifier = named("main")).create(ExportApi::class.java) } - single { get(qualifier = named("main")).create(GeneralApi::class.java) } - single { get(qualifier = named("main")).create(MessageApi::class.java) } - single { get(qualifier = named("main")).create(MetadataApi::class.java) } - single { get(qualifier = named("main")).create(MetricsApi::class.java) } - single { get(qualifier = named("main")).create(PrescriptionApi::class.java) } - single { get(qualifier = named("main")).create(SummaryApi::class.java) } - single { get(qualifier = named("main")).create(TaskApi::class.java) } - single { get(qualifier = named("main")).create(UserApi::class.java) } - - single { get().dataDao() } + + // API Service Implementations using expect/actual pattern + single { provideAlertApi(get()) } + single { provideAuthorizationApi(get()) } + single { provideBlobApi(get()) } + single { provideClinicApi(get()) } + single { provideConfirmationApi(get()) } + single { provideDataApi(get()) } +// single { provideExportApi(get()) } + single { provideGeneralApi(get()) } + single { provideMessageApi(get()) } + single { provideMetadataApi(get()) } + single { provideMetricsApi(get()) } + single { providePrescriptionApi(get()) } + single { provideSummaryApi(get()) } + single { provideTaskApi(get()) } + single { provideUserApi(get()) } + + single { get().basalAutomatedDataDao() } + single { get().bolusDataDao() } + single { get().continuousGlucoseDataDao() } + single { get().dosingDecisionDataDao() } + single { get().foodDataDao() } + single { get().insulinDataDao() } + single { get().deviceEventDataDao() } + single { get().cgmSettingsDataDao() } + single { get().controllerSettingsDataDao() } + single { get().pumpSettingsDataDao() } singleOf(::AlertRepositoryImpl) bind AlertRepository::class singleOf(::AuthorizationRepositoryImpl) bind AuthorizationRepository::class diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/AssociationDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/AssociationDto.kt new file mode 100644 index 0000000..8d329ab --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/AssociationDto.kt @@ -0,0 +1,62 @@ +package org.tidepool.sdk.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.tidepool.sdk.model.Association + +@Serializable +data class AssociationDto( + @SerialName("type") + val type: AssociationTypeDto?, + + val id: String?, + @SerialName("url") + val url: String?, + @SerialName("reason") + val reason: String?, +) { + @Serializable + enum class AssociationTypeDto { + + @SerialName("blob") + Blob, + + @SerialName("datum") + Datum, + + @SerialName("image") + Image, + + @SerialName("url") + Url, + ; + } +} + +fun AssociationDto.toDomain(): Association = Association( + type = type?.toDomain(), + id = id, + url = url, + reason = reason, +) + +fun Association.toDto(): AssociationDto = AssociationDto( + type = type?.toDto(), + id = id, + url = url, + reason = reason, +) + +fun AssociationDto.AssociationTypeDto.toDomain(): Association.AssociationType = when (this) { + AssociationDto.AssociationTypeDto.Blob -> Association.AssociationType.Blob + AssociationDto.AssociationTypeDto.Datum -> Association.AssociationType.Datum + AssociationDto.AssociationTypeDto.Image -> Association.AssociationType.Image + AssociationDto.AssociationTypeDto.Url -> Association.AssociationType.Url +} + +fun Association.AssociationType.toDto(): AssociationDto.AssociationTypeDto = when (this) { + Association.AssociationType.Blob -> AssociationDto.AssociationTypeDto.Blob + Association.AssociationType.Datum -> AssociationDto.AssociationTypeDto.Datum + Association.AssociationType.Image -> AssociationDto.AssociationTypeDto.Image + Association.AssociationType.Url -> AssociationDto.AssociationTypeDto.Url +} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/BloodGlucoseDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/BloodGlucoseDto.kt similarity index 75% rename from data/src/main/kotlin/org/tidepool/sdk/dto/BloodGlucoseDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/BloodGlucoseDto.kt index 7276f58..c9e76e9 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/BloodGlucoseDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/BloodGlucoseDto.kt @@ -6,7 +6,11 @@ import kotlinx.serialization.Serializable import org.tidepool.sdk.dto.BloodGlucoseDto.GlucoseReadingDto import org.tidepool.sdk.dto.BloodGlucoseDto.UnitsDto.MilligramsPerDeciliter import org.tidepool.sdk.dto.BloodGlucoseDto.UnitsDto.MillimolesPerLiter +import org.tidepool.sdk.dto.data.DosingDecisionDataDto +import org.tidepool.sdk.dto.data.toDomain +import org.tidepool.sdk.dto.data.toDto import org.tidepool.sdk.model.BloodGlucose +import org.tidepool.sdk.model.data.DosingDecisionData import kotlin.math.roundToInt import kotlin.time.Duration @@ -185,6 +189,38 @@ internal val Float.mmollDto: GlucoseReadingDto internal val Double.mmollDto: GlucoseReadingDto get() = GlucoseReadingDto(this, MillimolesPerLiter) internal fun BloodGlucose.Units.toDto() = when (this) { - BloodGlucose.Units.MilligramsPerDeciliter -> BloodGlucoseDto.UnitsDto.MilligramsPerDeciliter - BloodGlucose.Units.MillimolesPerLiter -> BloodGlucoseDto.UnitsDto.MillimolesPerLiter -} \ No newline at end of file + BloodGlucose.Units.MilligramsPerDeciliter -> MilligramsPerDeciliter + BloodGlucose.Units.MillimolesPerLiter -> MillimolesPerLiter +} + +fun BloodGlucose.Trend.toDto() = when (this) { + BloodGlucose.Trend.Constant -> BloodGlucoseDto.TrendDto.Constant + BloodGlucose.Trend.SlowFall -> BloodGlucoseDto.TrendDto.SlowFall + BloodGlucose.Trend.SlowRise -> BloodGlucoseDto.TrendDto.SlowRise + BloodGlucose.Trend.ModerateFall -> BloodGlucoseDto.TrendDto.ModerateFall + BloodGlucose.Trend.ModerateRise -> BloodGlucoseDto.TrendDto.ModerateRise + BloodGlucose.Trend.RapidFall -> BloodGlucoseDto.TrendDto.RapidFall + BloodGlucose.Trend.RapidRise -> BloodGlucoseDto.TrendDto.RapidRise +} + +fun BloodGlucoseDto.TrendDto.toDomain() = when (this) { + BloodGlucoseDto.TrendDto.Constant -> BloodGlucose.Trend.Constant + BloodGlucoseDto.TrendDto.SlowFall -> BloodGlucose.Trend.SlowFall + BloodGlucoseDto.TrendDto.SlowRise -> BloodGlucose.Trend.SlowRise + BloodGlucoseDto.TrendDto.ModerateFall -> BloodGlucose.Trend.ModerateFall + BloodGlucoseDto.TrendDto.ModerateRise -> BloodGlucose.Trend.ModerateRise + BloodGlucoseDto.TrendDto.RapidFall -> BloodGlucose.Trend.RapidFall + BloodGlucoseDto.TrendDto.RapidRise -> BloodGlucose.Trend.RapidRise +} + +fun DosingDecisionDataDto.UnitsDto.toDomain(): DosingDecisionData.Units = DosingDecisionData.Units( + bg = bg.toDomain(), + carb = carb.toDomain(), + insulin = insulin.toDomain() +) + +fun DosingDecisionData.Units.toDto() = DosingDecisionDataDto.UnitsDto( + bg = bg.toDto(), + carb = carb.toDto(), + insulin = insulin.toDto() +) \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/ResponseDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/ResponseDto.kt new file mode 100644 index 0000000..05a9d9a --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/ResponseDto.kt @@ -0,0 +1,40 @@ +package org.tidepool.sdk.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class ResponseDto( + @SerialName("data") + val data: List = emptyList(), + @SerialName("errors") + val errors: List = emptyList(), +) + +@Serializable +data class ErrorDto( + @SerialName("code") + val code: String, + @SerialName("title") + val title: String, + @SerialName("detail") + val detail: String, + @SerialName("source") + val source: ErrorSourceDto, + @SerialName("meta") + val meta: ErrorMetaDto, +) + +@Serializable +data class ErrorSourceDto( + @SerialName("pointer") + val pointer: String, +) + +@Serializable +data class ErrorMetaDto( + @SerialName("type") + val type: String, + @SerialName("deliveryType") + val deliveryType: String, +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/alert/AlertConfigDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/alert/AlertConfigDto.kt similarity index 88% rename from data/src/main/kotlin/org/tidepool/sdk/dto/alert/AlertConfigDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/alert/AlertConfigDto.kt index b0ef67d..0e5d559 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/alert/AlertConfigDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/alert/AlertConfigDto.kt @@ -1,7 +1,5 @@ package org.tidepool.sdk.dto.alert -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.alert.AlertConfig @@ -50,17 +48,12 @@ data class GlucoseAlertDto( ) @Serializable -@KonvertTo(ConnectionAlert::class, mapFunctionName = "toDomain") data class ConnectionAlertDto( @SerialName("enabled") val enabled: Boolean = false, @SerialName("delay") val delayMinutes: Int = 0, -) { - - @KonvertFrom(ConnectionAlert::class, mapFunctionName = "fromDomain") - companion object {} -} +) // Manual mapping functions for AlertConfigDto internal fun AlertConfigDto.toDomain(): AlertConfig = AlertConfig( @@ -82,10 +75,19 @@ internal fun AlertConfig.toDto(): AlertConfigDto = AlertConfigDto( low = low?.run { GlucoseAlertDto(enabled, threshold.toDto(), delayMinutes, repeatMinutes) }, high = high?.run { GlucoseAlertDto(enabled, threshold.toDto(), delayMinutes, repeatMinutes) }, noCommunication = noCommunication?.let { - ConnectionAlertDto.fromDomain(it) + it.toDto() }, notLooping = notLooping?.let { - ConnectionAlertDto.fromDomain(it) + it.toDto() }, ) +public fun ConnectionAlertDto.toDomain(): ConnectionAlert = ConnectionAlert( + enabled = enabled, + delayMinutes = delayMinutes +) +public fun ConnectionAlert.toDto(): ConnectionAlertDto = ConnectionAlertDto( + enabled = enabled, + delayMinutes = delayMinutes +) + diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/alert/GlucoseDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/alert/GlucoseDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/alert/GlucoseDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/alert/GlucoseDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/alert/GlucoseDtoSerializer.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/alert/GlucoseDtoSerializer.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/alert/GlucoseDtoSerializer.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/alert/GlucoseDtoSerializer.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/auth/ModifyUserPermissionsDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/auth/ModifyUserPermissionsDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/auth/ModifyUserPermissionsDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/auth/ModifyUserPermissionsDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/blob/BlobMetadataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/blob/BlobMetadataDto.kt similarity index 74% rename from data/src/main/kotlin/org/tidepool/sdk/dto/blob/BlobMetadataDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/blob/BlobMetadataDto.kt index fe3525e..7d0270d 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/blob/BlobMetadataDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/blob/BlobMetadataDto.kt @@ -1,14 +1,13 @@ package org.tidepool.sdk.dto.blob -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import org.tidepool.sdk.model.blob.BlobMetadata import org.tidepool.sdk.model.blob.BlobStatus import java.time.Instant @Serializable -@KonvertTo(org.tidepool.sdk.model.blob.BlobMetadata::class, mapFunctionName = "toDomain") data class BlobMetadataDto( @SerialName("id") val id: String, @@ -38,10 +37,10 @@ data class BlobMetadataDto( @Serializable enum class BlobStatusDto { - @kotlinx.serialization.SerialName("created") + @SerialName("created") Created, - @kotlinx.serialization.SerialName("available") + @SerialName("available") Available } @@ -53,4 +52,17 @@ internal fun BlobStatusDto.toDomain() = when (this) { internal fun BlobStatus.toDto() = when (this) { BlobStatus.Created -> BlobStatusDto.Created BlobStatus.Available -> BlobStatusDto.Available -} \ No newline at end of file +} + +fun BlobMetadataDto.toDomain(): BlobMetadata = BlobMetadata( + id = id, + userId = userId, + digestMD5 = digestMD5, + mediaType = mediaType, + size = size, + status = status.toDomain(), + createdTime = createdTime, + modifiedTime = modifiedTime, + deletedTime = deletedTime, + revision = revision +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/blob/DeviceLogsMetadataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/blob/DeviceLogsMetadataDto.kt similarity index 82% rename from data/src/main/kotlin/org/tidepool/sdk/dto/blob/DeviceLogsMetadataDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/blob/DeviceLogsMetadataDto.kt index 8d12fb5..b4eafd2 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/blob/DeviceLogsMetadataDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/blob/DeviceLogsMetadataDto.kt @@ -1,15 +1,14 @@ package org.tidepool.sdk.dto.blob -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.blob.DeviceLogContent import org.tidepool.sdk.model.blob.DeviceLogType +import org.tidepool.sdk.model.blob.DeviceLogsMetadata import java.time.Instant @Serializable -@KonvertTo(org.tidepool.sdk.model.blob.DeviceLogsMetadata::class, mapFunctionName = "toDomain") data class DeviceLogsMetadataDto( @SerialName("id") val id: String, @@ -32,8 +31,18 @@ data class DeviceLogsMetadataDto( val endAtTime: Instant ) +fun DeviceLogsMetadataDto.toDomain(): DeviceLogsMetadata = DeviceLogsMetadata( + id = id, + userId = userId, + digestMD5 = digestMD5, + mediaType = mediaType, + size = size, + createdTime = createdTime, + startAtTime = startAtTime, + endAtTime = endAtTime +) + @Serializable -@KonvertTo(DeviceLogContent::class, mapFunctionName = "toDomain") data class DeviceLogContentDto( @SerialName("type") val type: DeviceLogTypeDto, @@ -56,6 +65,14 @@ fun DeviceLogContent.toDto() = DeviceLogContentDto( message = message ) +fun DeviceLogContentDto.toDomain(): DeviceLogContent = DeviceLogContent( + type = type.toDomain(), + managerIdentifier = managerIdentifier, + deviceIdentifier = deviceIdentifier, + timestamp = timestamp, + message = message +) + @Serializable enum class DeviceLogTypeDto { diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/ClinicDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/ClinicDto.kt new file mode 100644 index 0000000..bea48e7 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/ClinicDto.kt @@ -0,0 +1,196 @@ +package org.tidepool.sdk.dto.clinic + +import kotlinx.serialization.Contextual +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.tidepool.sdk.dto.BloodGlucoseDto +import org.tidepool.sdk.model.BloodGlucose +import org.tidepool.sdk.model.clinic.Clinic +import org.tidepool.sdk.model.clinic.ClinicSize +import org.tidepool.sdk.model.clinic.ClinicType +import java.time.Instant + +@Serializable +data class ClinicDto( + @SerialName("id") + val id: String, + @SerialName("name") + val name: String, + @SerialName("shareCode") + val shareCode: String, + @SerialName("address") + val address: String? = null, + @SerialName("city") + val city: String? = null, + @SerialName("postalCode") + val postalCode: String? = null, + @SerialName("state") + val state: String? = null, + @SerialName("country") + val country: String? = null, + @SerialName("patientTags") + val patientTags: List? = null, + @SerialName("sites") + val sites: List? = null, + @SerialName("lastDeletedPatientTag") + val lastDeletedPatientTag: PatientTagDto? = null, + @SerialName("phoneNumbers") + val phoneNumbers: PhoneNumbersDto? = null, + @SerialName("clinicType") + val clinicType: ClinicTypeDto? = null, + @SerialName("clinicSize") + val clinicSize: ClinicSizeDto? = null, + @SerialName("canMigrate") + val canMigrate: Boolean, + @SerialName("website") + val website: String? = null, + @Contextual + @SerialName("createdTime") + val createdTime: Instant, + @Contextual + @SerialName("updatedTime") + val updatedTime: Instant, + @SerialName("tierDescription") + val tierDescription: String, + @SerialName("tier") + val tier: String, + @SerialName("preferredBgUnits") + val preferredBgUnits: BloodGlucoseDto.UnitsDto, + @SerialName("suppressedNotifications") + val suppressedNotifications: SuppressedNotificationsDto? = null, + @SerialName("timezone") + val timezone: String? = null, +) + +@Serializable +enum class ClinicTypeDto { + + @SerialName("provider_practice") + ProviderPractice, + + @SerialName("healthcare_system") + HealthcareSystem, + + @SerialName("veterinary_clinic") + VeterinaryClinic, + + @SerialName("researcher") + Researcher, + + @SerialName("other") + Other, +} + +@Serializable +enum class ClinicSizeDto { + + @SerialName("0-249") + Small, + + @SerialName("250-499") + Medium, + + @SerialName("500-999") + Large, + + @SerialName("1000+") + Huge, + ; +} + +fun ClinicDto.toDomain(): Clinic = Clinic( + id = id, + name = name, + shareCode = shareCode, + address = address, + city = city, + postalCode = postalCode, + state = state, + country = country, + patientTags = patientTags?.map { it.toDomain() }, + sites = sites?.map { it.toDomain() }, + lastDeletedPatientTag = lastDeletedPatientTag?.toDomain(), + phoneNumbers = phoneNumbers?.toDomain(), + clinicType = clinicType?.toDomain(), + clinicSize = clinicSize?.toDomain(), + canMigrate = canMigrate, + website = website, + createdTime = createdTime, + updatedTime = updatedTime, + tierDescription = tierDescription, + tier = tier, + preferredBgUnits = this.preferredBgUnits.toDomain(), + suppressedNotifications = suppressedNotifications?.toDomain(), + timezone = timezone +) + +private fun BloodGlucoseDto.UnitsDto.toDomain(): BloodGlucose.Units = when (this) { + BloodGlucoseDto.UnitsDto.MilligramsPerDeciliter -> BloodGlucose.Units.MilligramsPerDeciliter + BloodGlucoseDto.UnitsDto.MillimolesPerLiter -> BloodGlucose.Units.MillimolesPerLiter +} + +private fun ClinicSizeDto.toDomain(): ClinicSize = when (this) { + ClinicSizeDto.Small -> ClinicSize.Small + ClinicSizeDto.Medium -> ClinicSize.Medium + ClinicSizeDto.Large -> ClinicSize.Large + ClinicSizeDto.Huge -> ClinicSize.Huge +} + +private fun ClinicTypeDto.toDomain(): ClinicType = when (this) { + ClinicTypeDto.ProviderPractice -> ClinicType.ProviderPractice + ClinicTypeDto.HealthcareSystem -> ClinicType.HealthcareSystem + ClinicTypeDto.VeterinaryClinic -> ClinicType.VeterinaryClinic + ClinicTypeDto.Researcher -> ClinicType.Researcher + ClinicTypeDto.Other -> ClinicType.Other +} + +public fun Clinic.toDto(): ClinicDto = ClinicDto( + id = id, + name = name, + shareCode = shareCode, + address = address, + city = city, + postalCode = postalCode, + state = state, + country = country, + patientTags = patientTags?.map { it.toDto() }, + sites = sites?.map { it.toDto() }, + lastDeletedPatientTag = lastDeletedPatientTag?.let { it.toDto() }, + phoneNumbers = phoneNumbers?.let { it.toDto() }, + clinicType= clinicType?.toDto(), + clinicSize= clinicSize?.toDto(), + canMigrate = canMigrate, + website = website, + createdTime = createdTime, + updatedTime = updatedTime, + tierDescription = tierDescription, + tier = tier, + preferredBgUnits = when (preferredBgUnits) { + BloodGlucose.Units.MilligramsPerDeciliter -> BloodGlucoseDto.UnitsDto.MilligramsPerDeciliter + BloodGlucose.Units.MillimolesPerLiter -> BloodGlucoseDto.UnitsDto.MillimolesPerLiter + }, + suppressedNotifications = suppressedNotifications?.let { + it.toDto() + }, + timezone = timezone +) + +private fun BloodGlucose.Units.toDto(): BloodGlucoseDto.UnitsDto = when (this) { + BloodGlucose.Units.MilligramsPerDeciliter -> BloodGlucoseDto.UnitsDto.MilligramsPerDeciliter + BloodGlucose.Units.MillimolesPerLiter -> BloodGlucoseDto.UnitsDto.MillimolesPerLiter +} + +private fun ClinicSize.toDto(): ClinicSizeDto = when (this) { + ClinicSize.Small -> ClinicSizeDto.Small + ClinicSize.Medium -> ClinicSizeDto.Medium + ClinicSize.Large -> ClinicSizeDto.Large + ClinicSize.Huge -> ClinicSizeDto.Huge +} + +private fun ClinicType.toDto(): ClinicTypeDto = when (this) { + ClinicType.ProviderPractice -> ClinicTypeDto.ProviderPractice + ClinicType.HealthcareSystem -> ClinicTypeDto.HealthcareSystem + ClinicType.VeterinaryClinic -> ClinicTypeDto.VeterinaryClinic + ClinicType.Researcher -> ClinicTypeDto.Researcher + ClinicType.Other -> ClinicTypeDto.Other +} diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/ClinicianDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/ClinicianDto.kt new file mode 100644 index 0000000..67405d9 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/ClinicianDto.kt @@ -0,0 +1,75 @@ +package org.tidepool.sdk.dto.clinic + +import kotlinx.serialization.Contextual +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.tidepool.sdk.model.clinic.Clinician +import org.tidepool.sdk.model.clinic.ClinicianRole +import java.time.Instant + +@Serializable +data class ClinicianDto( + @SerialName("id") + val id: String? = null, + @SerialName("inviteId") + val inviteId: String? = null, + @SerialName("email") + val email: String, + @SerialName("name") + val name: String, + @SerialName("roles") + val roles: List, + @Contextual + @SerialName("createdTime") + val createdTime: Instant? = null, + @Contextual + @SerialName("updatedTime") + val updatedTime: Instant? = null, +) + +@Serializable +enum class ClinicianRoleDto { + @SerialName("CLINIC_ADMIN") + ClinicAdmin, + + @SerialName("CLINIC_MEMBER") + ClinicMember, + + @SerialName("PRESCRIBER") + Prescriber, + ; +} + +fun ClinicianDto.toDomain(): Clinician = Clinician( + id = id, + inviteId = inviteId, + email = email, + name = name, + roles = roles.map { it.toDomain() }, + createdTime = createdTime, + updatedTime = updatedTime +) + +private fun ClinicianRoleDto.toDomain(): ClinicianRole = when (this) { + ClinicianRoleDto.ClinicAdmin -> ClinicianRole.ClinicAdmin + ClinicianRoleDto.ClinicMember -> ClinicianRole.ClinicMember + ClinicianRoleDto.Prescriber -> ClinicianRole.Prescriber +} + +fun Clinician.toDto(): ClinicianDto = ClinicianDto( + id = id, + inviteId = inviteId, + email = email, + name = name, + roles = roles.map { + it.toDto() + }, + createdTime = createdTime, + updatedTime = updatedTime +) + +private fun ClinicianRole.toDto(): ClinicianRoleDto = when (this) { + ClinicianRole.ClinicAdmin -> ClinicianRoleDto.ClinicAdmin + ClinicianRole.ClinicMember -> ClinicianRoleDto.ClinicMember + ClinicianRole.Prescriber -> ClinicianRoleDto.Prescriber +} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PatientDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PatientDto.kt similarity index 55% rename from data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PatientDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PatientDto.kt index d926130..2199580 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PatientDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PatientDto.kt @@ -1,16 +1,13 @@ package org.tidepool.sdk.dto.clinic -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.clinic.Patient import org.tidepool.sdk.model.clinic.DataSource +import org.tidepool.sdk.model.clinic.Patient import java.time.Instant @Serializable -@KonvertTo(Patient::class, mapFunctionName = "toDomain") data class PatientDto( @SerialName("id") val id: String, @@ -32,13 +29,35 @@ data class PatientDto( @Contextual val createdTime: Instant? = null, @SerialName("updatedTime") @Contextual val updatedTime: Instant? = null -) { - @KonvertFrom(Patient::class, mapFunctionName = "fromDomain") - companion object -} +) + +fun PatientDto.toDomain(): Patient = Patient( + id = id, + email = email, + fullName = fullName, + birthDate = birthDate, + diagnosisDate = diagnosisDate, + targetDevices = targetDevices, + dataSources = dataSources?.map { it.toDomain() }, + patientTags = patientTags?.map { it.toDomain() }, + createdTime = createdTime, + updatedTime = updatedTime +) + +fun Patient.toDto(): PatientDto = PatientDto( + id = id, + email = email, + fullName = fullName, + birthDate = birthDate, + diagnosisDate = diagnosisDate, + targetDevices = targetDevices, + dataSources = dataSources?.map { it.toDto() }, + patientTags = patientTags?.map { it.toDto() }, + createdTime = createdTime, + updatedTime = updatedTime +) @Serializable -@KonvertTo(DataSource::class, mapFunctionName = "toDomain") data class DataSourceDto( @SerialName("providerName") val providerName: String, @@ -48,7 +67,18 @@ data class DataSourceDto( @Contextual val modifiedTime: Instant? = null, @SerialName("expirationTime") @Contextual val expirationTime: Instant? = null -) { - @KonvertFrom(DataSource::class, mapFunctionName = "fromDomain") - companion object -} \ No newline at end of file +) + +fun DataSourceDto.toDomain(): DataSource = DataSource( + providerName = providerName, + state = state, + modifiedTime = modifiedTime, + expirationTime = expirationTime, +) + +fun DataSource.toDto(): DataSourceDto = DataSourceDto( + providerName = providerName, + state = state, + modifiedTime = modifiedTime, + expirationTime = expirationTime, +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PatientTagDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PatientTagDto.kt similarity index 55% rename from data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PatientTagDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PatientTagDto.kt index 84caaf1..543f9df 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PatientTagDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PatientTagDto.kt @@ -1,19 +1,23 @@ package org.tidepool.sdk.dto.clinic -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.clinic.PatientTag @Serializable -@KonvertTo(PatientTag::class, mapFunctionName = "toDomain") data class PatientTagDto( @SerialName("id") val id: String, @SerialName("name") val name: String, -) { - @KonvertFrom(PatientTag::class, mapFunctionName = "fromDomain") - companion object -} \ No newline at end of file +) + +fun PatientTagDto.toDomain(): PatientTag = PatientTag( + id = id, + name = name +) + +fun PatientTag.toDto(): PatientTagDto = PatientTagDto( + id = id, + name = name +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PhoneNumbersDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PhoneNumbersDto.kt similarity index 53% rename from data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PhoneNumbersDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PhoneNumbersDto.kt index 9ddfc82..076934c 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/PhoneNumbersDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/PhoneNumbersDto.kt @@ -1,20 +1,23 @@ package org.tidepool.sdk.dto.clinic -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.clinic.Clinic import org.tidepool.sdk.model.clinic.PhoneNumbers @Serializable -@KonvertTo(PhoneNumbers::class, mapFunctionName = "toDomain") data class PhoneNumbersDto( @SerialName("phone") val phone: String? = null, @SerialName("fax") val fax: String? = null, -) { - @KonvertFrom(PhoneNumbers::class, mapFunctionName = "fromDomain") - companion object -} \ No newline at end of file +) + +fun PhoneNumbersDto.toDomain(): PhoneNumbers = PhoneNumbers( + phone = phone, + fax = fax +) + +fun PhoneNumbers.toDto(): PhoneNumbersDto = PhoneNumbersDto( + phone = phone, + fax = fax +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/SiteDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/SiteDto.kt similarity index 60% rename from data/src/main/kotlin/org/tidepool/sdk/dto/clinic/SiteDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/SiteDto.kt index 5daa1f5..78ef3c7 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/SiteDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/SiteDto.kt @@ -1,14 +1,10 @@ package org.tidepool.sdk.dto.clinic -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.clinic.Clinic import org.tidepool.sdk.model.clinic.Site @Serializable -@KonvertTo(Site::class, mapFunctionName = "toDomain") data class SiteDto( @SerialName("id") val id: String, @@ -24,7 +20,24 @@ data class SiteDto( val state: String? = null, @SerialName("country") val country: String? = null, -) { - @KonvertFrom(Site::class, mapFunctionName = "fromDomain") - companion object -} \ No newline at end of file +) + +public fun SiteDto.toDomain(): Site = Site( + id = id, + name = name, + address = address, + city = city, + postalCode = postalCode, + state = state, + country = country +) + +public fun Site.toDto(): SiteDto = SiteDto( + id = id, + name = name, + address = address, + city = city, + postalCode = postalCode, + state = state, + country = country +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/SuppressedNotificationsDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/SuppressedNotificationsDto.kt similarity index 54% rename from data/src/main/kotlin/org/tidepool/sdk/dto/clinic/SuppressedNotificationsDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/SuppressedNotificationsDto.kt index 23d9841..d282c13 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/SuppressedNotificationsDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/clinic/SuppressedNotificationsDto.kt @@ -1,14 +1,10 @@ package org.tidepool.sdk.dto.clinic -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.clinic.Clinic import org.tidepool.sdk.model.clinic.SuppressedNotifications @Serializable -@KonvertTo(SuppressedNotifications::class, mapFunctionName = "toDomain") data class SuppressedNotificationsDto( @SerialName("dexcomDataOutdated") val dexcomDataOutdated: Boolean? = null, @@ -18,7 +14,18 @@ data class SuppressedNotificationsDto( val initial: Boolean? = null, @SerialName("patientDataOutdated") val patientDataOutdated: Boolean? = null, -) { - @KonvertFrom(SuppressedNotifications::class, mapFunctionName = "fromDomain") - companion object -} \ No newline at end of file +) + +fun SuppressedNotificationsDto.toDomain() = SuppressedNotifications( + dexcomDataOutdated = dexcomDataOutdated, + dexcomDataStale = dexcomDataStale, + initial = initial, + patientDataOutdated = patientDataOutdated +) + +fun SuppressedNotifications.toDto() = SuppressedNotificationsDto( + dexcomDataOutdated = dexcomDataOutdated, + dexcomDataStale = dexcomDataStale, + initial = initial, + patientDataOutdated = patientDataOutdated +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/AcceptanceDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/AcceptanceDto.kt similarity index 77% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/AcceptanceDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/AcceptanceDto.kt index a497090..304e4ec 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/AcceptanceDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/AcceptanceDto.kt @@ -1,15 +1,18 @@ package org.tidepool.sdk.dto.confirmation -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.confirmations.Acceptance @Serializable -@KonvertTo(Acceptance::class, mapFunctionName = "toDomain") data class AcceptanceDto( @SerialName("password") val password: String, @SerialName("birthday") val birthday: String, // format: "2012-08-30" ) + +fun AcceptanceDto.toDomain(): Acceptance = Acceptance( + password = password, + birthday = birthday +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationDto.kt similarity index 98% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationDto.kt index d2741ba..703b012 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationDto.kt @@ -66,7 +66,7 @@ internal fun ConfirmationDto.toDomain(): Confirmation = Confirmation( } } }, - restrictions = restrictions?.toDomain(), + restrictions = null, expiresAt = expiresAt ) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationLookupDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationLookupDto.kt similarity index 63% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationLookupDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationLookupDto.kt index c66fdfa..544e53f 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationLookupDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationLookupDto.kt @@ -1,14 +1,15 @@ package org.tidepool.sdk.dto.confirmation -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.auth.TokenResponse import org.tidepool.sdk.model.confirmation.ConfirmationLookup @Serializable -@KonvertTo(value = ConfirmationLookup::class, mapFunctionName = "toDomain") data class ConfirmationLookupDto( @SerialName("key") val key: String, +) + +fun ConfirmationLookupDto.toDomain(): ConfirmationLookup = ConfirmationLookup( + key = key ) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationStatusDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationStatusDto.kt similarity index 89% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationStatusDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationStatusDto.kt index bf4f7ee..c22c4f1 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationStatusDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationStatusDto.kt @@ -1,9 +1,7 @@ package org.tidepool.sdk.dto.confirmation -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.auth.TokenResponse import org.tidepool.sdk.model.confirmation.ConfirmationStatus @Serializable diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationTypeDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationTypeDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationTypeDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationTypeDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationUpsertDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationUpsertDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationUpsertDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/ConfirmationUpsertDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/InvitationDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/InvitationDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/InvitationDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/InvitationDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/PasswordChangeDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/PasswordChangeDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/PasswordChangeDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/PasswordChangeDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/RestrictionsDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/RestrictionsDto.kt similarity index 66% rename from data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/RestrictionsDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/RestrictionsDto.kt index b2bacc9..685a8de 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/confirmation/RestrictionsDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/confirmation/RestrictionsDto.kt @@ -1,16 +1,18 @@ package org.tidepool.sdk.dto.confirmation -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.confirmation.ConfirmationStatus import org.tidepool.sdk.model.confirmation.Restrictions @Serializable -@KonvertTo(value = Restrictions::class, mapFunctionName = "toDomain") data class RestrictionsDto( @SerialName("canAccept") val canAccept: Boolean, @SerialName("requiredIdp") val requiredIdp: String? +) + +fun RestrictionsDto.toDomain(): Restrictions = Restrictions( + canAccept = canAccept, + requiredIdp = requiredIdp ) \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BasalAutomatedDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BasalAutomatedDataDto.kt new file mode 100644 index 0000000..8d54b38 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BasalAutomatedDataDto.kt @@ -0,0 +1,120 @@ +package org.tidepool.sdk.dto.data + +import kotlinx.serialization.Contextual +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.tidepool.sdk.model.data.BasalAutomatedData +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +// TODO: Finish implementing automated.v1 +@Serializable +data class BasalAutomatedDataDto( + override val id: String = "", + override val type: DataTypeDto = DataTypeDto.Alert, + @Contextual + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + @Contextual + override val clockDriftOffset: Duration? = null, + @Contextual + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + @Contextual + override val timeZone: TimeZone? = null, + @Contextual + override val timeZoneOffset: Int? = null, + + @SerialName("deliveryType") + val deliveryType: DeliveryTypeDto, + @SerialName("duration") + val duration: Int, + @SerialName("expectedDuration") + val expectedDuration: Int? = null, + @SerialName("rate") + val rate: Double = -1.0, + @SerialName("scheduleName") + val scheduleName: String? = null, +) : BaseDataDto() { + val insulinFormulation: Nothing + get() = TODO("schema \"formulation.v1\" not implemented") + val suppressed: Nothing + get() = TODO("schema \"scheduled.v1\" not implemented") + + @Serializable + enum class DeliveryTypeDto { + + @SerialName("automated") + Automated, + + @SerialName("scheduled") + Scheduled, + + @SerialName("suspend") + Suspend, + + @SerialName("temp") + Temp, + } +} + +fun BasalAutomatedDataDto.toDomain(): BasalAutomatedData = BasalAutomatedData( + id = id, + type = this.type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + deliveryType = this.deliveryType.toDomain(), + duration = duration, + expectedDuration = expectedDuration, + rate = rate, + scheduleName = scheduleName +) + +fun BasalAutomatedDataDto.DeliveryTypeDto.toDomain(): BasalAutomatedData.DeliveryType = when (this) { + BasalAutomatedDataDto.DeliveryTypeDto.Automated -> BasalAutomatedData.DeliveryType.Automated + BasalAutomatedDataDto.DeliveryTypeDto.Scheduled -> BasalAutomatedData.DeliveryType.Scheduled + BasalAutomatedDataDto.DeliveryTypeDto.Suspend -> BasalAutomatedData.DeliveryType.Suspend + BasalAutomatedDataDto.DeliveryTypeDto.Temp -> BasalAutomatedData.DeliveryType.Temp +} + +fun BasalAutomatedData.toDto(): BasalAutomatedDataDto = BasalAutomatedDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + deliveryType = deliveryType.toDto(), + duration = duration, + expectedDuration = expectedDuration, + rate = rate, + scheduleName = scheduleName +) + +fun BasalAutomatedData.DeliveryType.toDto(): BasalAutomatedDataDto.DeliveryTypeDto = when (this) { + BasalAutomatedData.DeliveryType.Automated -> BasalAutomatedDataDto.DeliveryTypeDto.Automated + BasalAutomatedData.DeliveryType.Scheduled -> BasalAutomatedDataDto.DeliveryTypeDto.Scheduled + BasalAutomatedData.DeliveryType.Suspend -> BasalAutomatedDataDto.DeliveryTypeDto.Suspend + BasalAutomatedData.DeliveryType.Temp -> BasalAutomatedDataDto.DeliveryTypeDto.Temp +} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/BaseDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BaseDataDto.kt similarity index 60% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/BaseDataDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BaseDataDto.kt index ebe3aa4..ed186f6 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/BaseDataDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BaseDataDto.kt @@ -8,17 +8,22 @@ import org.tidepool.sdk.dto.AssociationDto import org.tidepool.sdk.model.data.BasalAutomatedData import org.tidepool.sdk.model.data.BaseData import org.tidepool.sdk.model.data.BolusData +import org.tidepool.sdk.model.data.CgmSettingsData import org.tidepool.sdk.model.data.ContinuousGlucoseData +import org.tidepool.sdk.model.data.ControllerSettingsData import org.tidepool.sdk.model.data.DataType +import org.tidepool.sdk.model.data.DeviceEventData import org.tidepool.sdk.model.data.DosingDecisionData import org.tidepool.sdk.model.data.FoodData import org.tidepool.sdk.model.data.InsulinData +import org.tidepool.sdk.model.data.PumpSettingsData import java.time.Instant import java.util.TimeZone import kotlin.reflect.KClass import kotlin.time.Duration // TODO: finish implementing base.v1 +@Serializable abstract class BaseDataDto { @SerialName("id") abstract val id: String @@ -44,90 +49,117 @@ abstract class BaseDataDto { @SerialName("timeZone") abstract val timeZone: TimeZone? @SerialName("timeZoneOffset") - abstract val timeZoneOffset: Duration? - - companion object { - internal fun fromDomain(domain: BaseData): BaseDataDto = when (domain) { - is BasalAutomatedData -> BasalAutomatedDataDto.fromDomain(domain) - is BolusData -> BolusDataDto.fromDomain(domain) - is ContinuousGlucoseData -> ContinuousGlucoseDataDto.fromDomain(domain) - is DosingDecisionData -> DosingDecisionDataDto.fromDomain(domain) - is FoodData -> FoodDataDto.fromDomain(domain) - is InsulinData -> InsulinDataDto.fromDomain(domain) - } - } - + abstract val timeZoneOffset: Int? + val location: Nothing get() = TODO("schema \"\" not implemented") - + @Serializable enum class DataTypeDto(override val subclassType: KClass) : ResultType { - + @SerialName("alert") Alert(BaseDataDto::class), - + @SerialName("basal") Basal(BasalAutomatedDataDto::class), - + @SerialName("bloodKetone") BloodKetone(BaseDataDto::class), - + @SerialName("bolus") Bolus(BolusDataDto::class), - + @SerialName("wizard") Calculator(BaseDataDto::class), - + @SerialName("cbg") Cbg(ContinuousGlucoseDataDto::class), - + @SerialName("cgmSettings") - CgmSettings(BaseDataDto::class), - + CgmSettings(CgmSettingsDataDto::class), + @SerialName("controllerSettings") - ControllerSettings(BaseDataDto::class), - + ControllerSettings(ControllerSettingsDataDto::class), + @SerialName("controllerStatus") ControllerStatus(BaseDataDto::class), - + @SerialName("deviceEvent") - DeviceEvent(BaseDataDto::class), - + DeviceEvent(DeviceEventDataDto::class), + @SerialName("dosingDecision") DosingDecision(DosingDecisionDataDto::class), - + @SerialName("food") Food(FoodDataDto::class), - + @SerialName("insulin") Insulin(InsulinDataDto::class), - + @SerialName("physicalActivity") PhysicalActivity(BaseDataDto::class), - + @SerialName("pumpSettings") - PumpSettings(BaseDataDto::class), - + PumpSettings(PumpSettingsDataDto::class), + @SerialName("pumpStatus") PumpStatus(BaseDataDto::class), - + @SerialName("reportedState") ReportedState(BaseDataDto::class), - + @SerialName("smbg") Smbg(BaseDataDto::class) } } internal fun BaseDataDto.toDomain(): BaseData = when (this) { - is BasalAutomatedDataDto -> toDomain() - is BolusDataDto -> toDomain() - is ContinuousGlucoseDataDto -> toDomain() - is DosingDecisionDataDto -> toDomain() - is FoodDataDto -> toDomain() - is InsulinDataDto -> toDomain() - else -> throw IllegalArgumentException("Unknown BaseDataDto subtype: ${this::class}") + is BasalAutomatedDataDto -> toDomain() + is BolusDataDto -> toDomain() + is ContinuousGlucoseDataDto -> toDomain() + is DosingDecisionDataDto -> toDomain() + is FoodDataDto -> toDomain() + is InsulinDataDto -> toDomain() + is CgmSettingsDataDto -> toDomain() + is ControllerSettingsDataDto -> toDomain() + is PumpSettingsDataDto -> toDomain() + is DeviceEventDataDto -> toDomain() + else -> throw IllegalArgumentException("Unknown BaseDataDto type: ${this::class.simpleName}") +} + +fun BaseDataDto.DataTypeDto.toDomain(): DataType = when (this) { + BaseDataDto.DataTypeDto.Alert -> DataType.Alert + BaseDataDto.DataTypeDto.Basal -> DataType.Basal + BaseDataDto.DataTypeDto.BloodKetone -> DataType.BloodKetone + BaseDataDto.DataTypeDto.Bolus -> DataType.Bolus + BaseDataDto.DataTypeDto.Calculator -> DataType.Calculator + BaseDataDto.DataTypeDto.Cbg -> DataType.Cbg + BaseDataDto.DataTypeDto.CgmSettings -> DataType.CgmSettings + BaseDataDto.DataTypeDto.ControllerSettings -> DataType.ControllerSettings + BaseDataDto.DataTypeDto.ControllerStatus -> DataType.ControllerStatus + BaseDataDto.DataTypeDto.DeviceEvent -> DataType.DeviceEvent + BaseDataDto.DataTypeDto.DosingDecision -> DataType.DosingDecision + BaseDataDto.DataTypeDto.Food -> DataType.Food + BaseDataDto.DataTypeDto.Insulin -> DataType.Insulin + BaseDataDto.DataTypeDto.PhysicalActivity -> DataType.PhysicalActivity + BaseDataDto.DataTypeDto.PumpSettings -> DataType.PumpSettings + BaseDataDto.DataTypeDto.PumpStatus -> DataType.PumpStatus + BaseDataDto.DataTypeDto.ReportedState -> DataType.ReportedState + BaseDataDto.DataTypeDto.Smbg -> DataType.Smbg +} + +internal fun BaseData.toDto(): BaseDataDto = when (this) { + is BasalAutomatedData -> toDto() + is BolusData -> toDto() + is ContinuousGlucoseData -> toDto() + is DosingDecisionData -> toDto() + is FoodData -> toDto() + is InsulinData -> toDto() + is CgmSettingsData -> toDto() + is ControllerSettingsData -> toDto() + is PumpSettingsData -> toDto() + is DeviceEventData -> toDto() } internal fun DataType.toDto(): BaseDataDto.DataTypeDto = when (this) { diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BolusDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BolusDataDto.kt new file mode 100644 index 0000000..f958cd4 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/BolusDataDto.kt @@ -0,0 +1,138 @@ +package org.tidepool.sdk.dto.data + +import kotlinx.serialization.Contextual +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto +import org.tidepool.sdk.model.data.BolusData +import org.tidepool.sdk.model.data.BolusSubtype +import org.tidepool.sdk.model.data.DeliveryContext +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +// schema bolus.v1 +// line 2330 +@Serializable +data class BolusDataDto( + override val id: String = "", + override val type: DataTypeDto = DataTypeDto.Alert, + @Contextual + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + @Contextual + override val clockDriftOffset: Duration? = null, + @Contextual + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + @Contextual + override val timeZone: TimeZone? = null, + @Contextual + override val timeZoneOffset: Int? = null, + + @SerialName("subType") + val subType: BolusSubtypeDto = BolusSubtypeDto.Normal, + @SerialName("deliveryContext") + val deliveryContext: DeliveryContextDto, +) : BaseDataDto() { + + val insulinFormulation: Nothing + get() = TODO("schema \"formulation.v1\" not implemented") +} + +@Serializable +enum class BolusSubtypeDto { + @SerialName("automated") + Automated, + @SerialName("dual/square") + DualSquare, + @SerialName("normal") + Normal, + @SerialName("square") + Square, + ; +} + +@Serializable +enum class DeliveryContextDto { + + @SerialName("device") + Device, + + @SerialName("algorithm") + Algorithm, + + @SerialName("remote") + Remote, + + @SerialName("undetermined") + Undetermined, + ; +} + +fun BolusDataDto.toDomain(): BolusData = BolusData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + subType = subType.toDomain(), + deliveryContext = deliveryContext.toDomain(), +) + +fun DeliveryContextDto.toDomain(): DeliveryContext = when (this) { + DeliveryContextDto.Device -> DeliveryContext.Device + DeliveryContextDto.Algorithm -> DeliveryContext.Algorithm + DeliveryContextDto.Remote -> DeliveryContext.Remote + DeliveryContextDto.Undetermined -> DeliveryContext.Undetermined +} + +fun BolusSubtypeDto.toDomain(): BolusSubtype = when (this) { + BolusSubtypeDto.Automated -> BolusSubtype.Automated + BolusSubtypeDto.DualSquare -> BolusSubtype.DualSquare + BolusSubtypeDto.Normal -> BolusSubtype.Normal + BolusSubtypeDto.Square -> BolusSubtype.Square +} + +fun BolusData.toDto(): BolusDataDto = BolusDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + subType = subType.toDto(), + deliveryContext = deliveryContext.toDto(), +) + +fun DeliveryContext.toDto(): DeliveryContextDto = when (this) { + DeliveryContext.Device -> DeliveryContextDto.Device + DeliveryContext.Algorithm -> DeliveryContextDto.Algorithm + DeliveryContext.Remote -> DeliveryContextDto.Remote + DeliveryContext.Undetermined -> DeliveryContextDto.Undetermined +} + +fun BolusSubtype.toDto(): BolusSubtypeDto = when (this) { + BolusSubtype.Automated -> BolusSubtypeDto.Automated + BolusSubtype.DualSquare -> BolusSubtypeDto.DualSquare + BolusSubtype.Normal -> BolusSubtypeDto.Normal + BolusSubtype.Square -> BolusSubtypeDto.Square +} \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/CgmSettingsDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/CgmSettingsDataDto.kt new file mode 100644 index 0000000..3714be2 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/CgmSettingsDataDto.kt @@ -0,0 +1,62 @@ +package org.tidepool.sdk.dto.data + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto +import org.tidepool.sdk.model.data.CgmSettingsData +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +@Serializable +data class CgmSettingsDataDto( + override val id: String = "", + override val type: BaseDataDto.DataTypeDto = BaseDataDto.DataTypeDto.CgmSettings, + @Contextual + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + @Contextual + override val clockDriftOffset: Duration? = null, + @Contextual + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + @Contextual + override val timeZone: TimeZone? = null, + @Contextual + override val timeZoneOffset: Int? = null, +) : BaseDataDto() + +fun CgmSettingsDataDto.toDomain(): CgmSettingsData = CgmSettingsData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) + +fun CgmSettingsData.toDto(): CgmSettingsDataDto = CgmSettingsDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/ContinuousGlucoseDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/ContinuousGlucoseDataDto.kt similarity index 55% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/ContinuousGlucoseDataDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/ContinuousGlucoseDataDto.kt index 5bc7c5a..fb4930f 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/ContinuousGlucoseDataDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/ContinuousGlucoseDataDto.kt @@ -1,21 +1,19 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.dto.AssociationDto import org.tidepool.sdk.dto.BloodGlucoseDto import org.tidepool.sdk.dto.BloodGlucoseDto.GlucoseReadingDto -import org.tidepool.sdk.dto.data.BaseDataDto.DataTypeDto +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto import org.tidepool.sdk.model.data.ContinuousGlucoseData import java.time.Instant import java.util.TimeZone import kotlin.time.Duration @Serializable -@KonvertTo(ContinuousGlucoseData::class, mapFunctionName = "toDomain") data class ContinuousGlucoseDataDto( override val id: String = "", override val type: DataTypeDto = DataTypeDto.Alert, @@ -33,8 +31,8 @@ data class ContinuousGlucoseDataDto( @Contextual override val timeZone: TimeZone? = null, @Contextual - override val timeZoneOffset: Duration? = null, - + override val timeZoneOffset: Int? = null, + @SerialName("value") val value: Double? = null, @SerialName("units") @@ -42,12 +40,9 @@ data class ContinuousGlucoseDataDto( @SerialName("trend") val trend: BloodGlucoseDto.TrendDto? = null, @SerialName("trendRate") - val trendRate: Double? = null + val trendRate: Double? = null, ) : BaseDataDto() { - - @KonvertFrom(ContinuousGlucoseData::class, mapFunctionName = "fromDomain") - companion object {} - + val reading: GlucoseReadingDto? by lazy { value?.let { value -> units?.let { units -> @@ -55,4 +50,42 @@ data class ContinuousGlucoseDataDto( } } } -} \ No newline at end of file +} + +fun ContinuousGlucoseDataDto.toDomain(): ContinuousGlucoseData = ContinuousGlucoseData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + value = value, + units = units?.toDomain(), + trend = trend?.toDomain(), + trendRate = trendRate, +) + +fun ContinuousGlucoseData.toDto() = ContinuousGlucoseDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + value = value, + units = units?.toDto(), + trend = trend?.toDto(), + trendRate = trendRate, +) \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/ControllerSettingsDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/ControllerSettingsDataDto.kt new file mode 100644 index 0000000..3389741 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/ControllerSettingsDataDto.kt @@ -0,0 +1,62 @@ +package org.tidepool.sdk.dto.data + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto +import org.tidepool.sdk.model.data.ControllerSettingsData +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +@Serializable +data class ControllerSettingsDataDto( + override val id: String = "", + override val type: BaseDataDto.DataTypeDto = BaseDataDto.DataTypeDto.ControllerSettings, + @Contextual + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + @Contextual + override val clockDriftOffset: Duration? = null, + @Contextual + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + @Contextual + override val timeZone: TimeZone? = null, + @Contextual + override val timeZoneOffset: Int? = null, +) : BaseDataDto() + +fun ControllerSettingsDataDto.toDomain(): ControllerSettingsData = ControllerSettingsData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) + +fun ControllerSettingsData.toDto(): ControllerSettingsDataDto = ControllerSettingsDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DataSetDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DataSetDto.kt new file mode 100644 index 0000000..6eac19c --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DataSetDto.kt @@ -0,0 +1,193 @@ +package org.tidepool.sdk.dto.data + +import kotlinx.serialization.Contextual +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import java.time.Instant +import kotlin.time.Duration +import org.tidepool.sdk.model.data.ClientSoftware +import org.tidepool.sdk.model.data.DataSet +import org.tidepool.sdk.model.data.DeduplicatorDescriptor +import org.tidepool.sdk.model.data.DeviceTag + +@Serializable +data class DataSetDto( + @SerialName("annotations") + val annotations: List>? = null, + @SerialName("byUser") + val byUser: String? = null, + @SerialName("client") + val client: ClientSoftwareDto? = null, + @SerialName("clockDriftOffset") + @Contextual val clockDriftOffset: Duration? = null, + @SerialName("computerTime") + val computerTime: String? = null, + @SerialName("conversionOffset") + @Contextual val conversionOffset: Duration? = null, + @SerialName("createdTime") + @Contextual val createdTime: Instant? = null, + @SerialName("createdUserId") + val createdUserId: String? = null, + @SerialName("dataSetType") + val dataSetType: String? = null, + @SerialName("deduplicator") + val deduplicator: DeduplicatorDescriptorDto? = null, + @SerialName("deletedTime") + @Contextual val deletedTime: Instant? = null, + @SerialName("deletedUserId") + val deletedUserId: String? = null, + @SerialName("deviceId") + val deviceId: String? = null, + @SerialName("deviceManufacturers") + val deviceManufacturers: List? = null, + @SerialName("deviceModel") + val deviceModel: String? = null, + @SerialName("deviceSerialNumber") + val deviceSerialNumber: String? = null, + @SerialName("deviceTags") + val deviceTags: List? = null, + @SerialName("id") + val id: String? = null, + @SerialName("modifiedTime") + @Contextual val modifiedTime: Instant? = null, + @SerialName("modifiedUserId") + val modifiedUserId: String? = null, + @SerialName("state") + val state: String? = null, + @SerialName("time") + @Contextual val time: Instant? = null, + @SerialName("timeProcessing") + val timeProcessing: String? = null, + @SerialName("timezone") + val timezone: String? = null, + @SerialName("timezoneOffset") + val timeZoneOffset: Int? = null, + @SerialName("type") + val type: String? = null, + @SerialName("uploadId") + val uploadId: String? = null, + @SerialName("version") + val version: String? = null, +) + +@Serializable +data class ClientSoftwareDto( + @SerialName("name") + val name: String? = null, + @SerialName("version") + val version: String? = null, +) + +@Serializable +data class DeduplicatorDescriptorDto( + @SerialName("name") + val name: String? = null, + @SerialName("version") + val version: String? = null, +) + +@Serializable +enum class DeviceTagDto { + @SerialName("bgm") + Bgm, + + @SerialName("cgm") + Cgm, + + @SerialName("insulin-pump") + InsulinPump, +} + +fun ClientSoftwareDto.toDomain(): ClientSoftware = ClientSoftware( + name = name, + version = version +) + +fun ClientSoftware.toDto(): ClientSoftwareDto = ClientSoftwareDto( + name = name, + version = version +) + +fun DataSetDto.toDomain(): DataSet = DataSet( + annotations = annotations, + byUser = byUser, + client = client?.toDomain(), + clockDriftOffset = clockDriftOffset, + computerTime = computerTime, + conversionOffset = conversionOffset, + createdTime = createdTime, + createdUserId = createdUserId, + dataSetType = dataSetType, + deduplicator = deduplicator?.toDomain(), + deletedTime = deletedTime, + deletedUserId = deletedUserId, + deviceId = deviceId, + deviceManufacturers = deviceManufacturers, + deviceModel = deviceModel, + deviceSerialNumber = deviceSerialNumber, + deviceTags = deviceTags?.map { it.toDomain() }, + id = id, + modifiedTime = modifiedTime, + modifiedUserId = modifiedUserId, + state = state, + time = time, + timeProcessing = timeProcessing, + timezone = timezone, + timeZoneOffset = timeZoneOffset, + type = type, + uploadId = uploadId, + version = version +) + +fun DataSet.toDto(): DataSetDto = DataSetDto( + annotations = annotations, + byUser = byUser, + client = client?.toDto(), + clockDriftOffset = clockDriftOffset, + computerTime = computerTime, + conversionOffset = conversionOffset, + createdTime = createdTime, + createdUserId = createdUserId, + dataSetType = dataSetType, + deduplicator = deduplicator?.toDto(), + deletedTime = deletedTime, + deletedUserId = deletedUserId, + deviceId = deviceId, + deviceManufacturers = deviceManufacturers, + deviceModel = deviceModel, + deviceSerialNumber = deviceSerialNumber, + deviceTags = deviceTags?.map { it.toDto() }, + id = id, + modifiedTime = modifiedTime, + modifiedUserId = modifiedUserId, + state = state, + time = time, + timeProcessing = timeProcessing, + timezone = timezone, + timeZoneOffset = timeZoneOffset, + type = type, + uploadId = uploadId, + version = version +) + +fun DeduplicatorDescriptorDto.toDomain(): DeduplicatorDescriptor = DeduplicatorDescriptor( + name = name, + version = version, +) + +fun DeduplicatorDescriptor.toDto(): DeduplicatorDescriptorDto = DeduplicatorDescriptorDto( + name = name, + version = version, +) + +fun DeviceTagDto.toDomain(): DeviceTag = when (this) { + DeviceTagDto.Bgm -> DeviceTag.Bgm + DeviceTagDto.Cgm -> DeviceTag.Cgm + DeviceTagDto.InsulinPump -> DeviceTag.InsulinPump +} + +fun DeviceTag.toDto(): DeviceTagDto = when (this) { + DeviceTag.Bgm -> DeviceTagDto.Bgm + DeviceTag.Cgm -> DeviceTagDto.Cgm + DeviceTag.InsulinPump -> DeviceTagDto.InsulinPump +} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/DataSourceDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DataSourceDto.kt similarity index 57% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/DataSourceDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DataSourceDto.kt index 93d273e..de9e79d 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/DataSourceDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DataSourceDto.kt @@ -1,7 +1,5 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -9,7 +7,6 @@ import org.tidepool.sdk.model.data.DataSource import java.time.Instant @Serializable -@KonvertTo(DataSource::class, mapFunctionName = "toDomain") data class DataSourceDto( @SerialName("createdTime") @Contextual val createdTime: Instant? = null, @@ -33,7 +30,32 @@ data class DataSourceDto( val providerType: String? = null, @SerialName("state") val state: String? = null -) { - @KonvertFrom(DataSource::class, mapFunctionName = "fromDomain") - companion object {} -} \ No newline at end of file +) + +fun DataSourceDto.toDomain(): DataSource = DataSource( + createdTime = createdTime, + dataSetIds = dataSetIds, + earliestDataTime = earliestDataTime, + id = id, + lastImportTime = lastImportTime, + latestDataTime = latestDataTime, + modifiedTime = modifiedTime, + providerName = providerName, + providerSessionId = providerSessionId, + providerType = providerType, + state = state +) + +fun DataSource.toDto(): DataSourceDto = DataSourceDto( + createdTime = createdTime, + dataSetIds = dataSetIds, + earliestDataTime = earliestDataTime, + id = id, + lastImportTime = lastImportTime, + latestDataTime = latestDataTime, + modifiedTime = modifiedTime, + providerName = providerName, + providerSessionId = providerSessionId, + providerType = providerType, + state = state +) \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DeviceEventDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DeviceEventDataDto.kt new file mode 100644 index 0000000..20bdb92 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DeviceEventDataDto.kt @@ -0,0 +1,114 @@ +package org.tidepool.sdk.dto.data + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Contextual +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto +import org.tidepool.sdk.model.data.DeviceEventData +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +@Serializable +data class DeviceEventDataDto( + override val id: String = "", + override val type: DataTypeDto = DataTypeDto.DeviceEvent, + @Contextual + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + @Contextual + override val clockDriftOffset: Duration? = null, + @Contextual + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + @Contextual + override val timeZone: TimeZone? = null, + @Contextual + override val timeZoneOffset: Int? = null, + + @SerialName("subType") + val subType: SubTypeDto, + @SerialName("deviceIdentifier") + val deviceIdentifier: String? = null, + @SerialName("expectedLifetimeSeconds") + val expectedLifetimeSeconds: Double? = null, + @SerialName("warmupPeriodSeconds") + val warmupPeriodSeconds: Double? = null, + @SerialName("failureMessage") + val failureMessage: String? = null, +) : BaseDataDto() { + + @Serializable + enum class SubTypeDto { + @SerialName("sensorStart") + SensorStart, + + @SerialName("sensorEnd") + SensorEnd, + + @SerialName("transmitterStart") + TransmitterStart, + + @SerialName("transmitterEnd") + TransmitterEnd, + } +} + +internal fun DeviceEventDataDto.SubTypeDto.toDomain(): DeviceEventData.SubType = when (this) { + DeviceEventDataDto.SubTypeDto.SensorStart -> DeviceEventData.SubType.SensorStart + DeviceEventDataDto.SubTypeDto.SensorEnd -> DeviceEventData.SubType.SensorEnd + DeviceEventDataDto.SubTypeDto.TransmitterStart -> DeviceEventData.SubType.TransmitterStart + DeviceEventDataDto.SubTypeDto.TransmitterEnd -> DeviceEventData.SubType.TransmitterEnd +} + +internal fun DeviceEventData.SubType.toDto(): DeviceEventDataDto.SubTypeDto = when (this) { + DeviceEventData.SubType.SensorStart -> DeviceEventDataDto.SubTypeDto.SensorStart + DeviceEventData.SubType.SensorEnd -> DeviceEventDataDto.SubTypeDto.SensorEnd + DeviceEventData.SubType.TransmitterStart -> DeviceEventDataDto.SubTypeDto.TransmitterStart + DeviceEventData.SubType.TransmitterEnd -> DeviceEventDataDto.SubTypeDto.TransmitterEnd +} + +fun DeviceEventDataDto.toDomain(): DeviceEventData = DeviceEventData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + subType = subType.toDomain(), + deviceIdentifier = deviceIdentifier, + expectedLifetimeSeconds = expectedLifetimeSeconds, + warmupPeriodSeconds = warmupPeriodSeconds, + failureMessage = failureMessage, +) + +fun DeviceEventData.toDto(): DeviceEventDataDto = DeviceEventDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + subType = subType.toDto(), + deviceIdentifier = deviceIdentifier, + expectedLifetimeSeconds = expectedLifetimeSeconds, + warmupPeriodSeconds = warmupPeriodSeconds, + failureMessage = failureMessage, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/DosingDecisionDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DosingDecisionDataDto.kt similarity index 57% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/DosingDecisionDataDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DosingDecisionDataDto.kt index f9a8441..b91fa51 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/DosingDecisionDataDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/DosingDecisionDataDto.kt @@ -1,14 +1,14 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Contextual import org.tidepool.sdk.dto.AssociationDto import org.tidepool.sdk.dto.BloodGlucoseDto +import org.tidepool.sdk.dto.data.DosingDecisionDataDto.* +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto import org.tidepool.sdk.model.BloodGlucose -import org.tidepool.sdk.model.data.BasalAutomatedData import org.tidepool.sdk.model.data.DosingDecisionData import java.time.Instant import java.util.TimeZone @@ -16,10 +16,9 @@ import kotlin.time.Duration // TODO: finish implementing dosingdecision.v1 @Serializable -@KonvertTo(DosingDecisionData::class, mapFunctionName = "toDomain") data class DosingDecisionDataDto( override val id: String = "", - override val type: DataTypeDto = DataTypeDto.Alert, + override val type: DataTypeDto = DataTypeDto.DosingDecision, @Contextual override val time: Instant? = null, override val annotations: List> = emptyList(), @@ -34,7 +33,7 @@ data class DosingDecisionDataDto( @Contextual override val timeZone: TimeZone? = null, @Contextual - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, @SerialName("reason") val reason: String, @@ -54,9 +53,6 @@ data class DosingDecisionDataDto( val units: UnitsDto = UnitsDto(), ) : BaseDataDto() { - @KonvertFrom(DosingDecisionData::class, mapFunctionName = "fromDomain") - companion object {} - val originalFood: Nothing get() = TODO("backing object not implemented") val food: Nothing @@ -75,70 +71,44 @@ data class DosingDecisionDataDto( get() = TODO("schema \"issue.v1\" not implemented") @Serializable - @KonvertTo(DosingDecisionData.CarbsOnBoard::class, mapFunctionName = "toDomain") data class CarbsOnBoardDto( @Contextual @SerialName("time") val time: Instant? = null, @SerialName("amount") val amount: Double = -1.0, - ) { - - @KonvertFrom(DosingDecisionData.CarbsOnBoard::class, mapFunctionName = "fromDomain") - companion object {} - } + ) @Serializable - @KonvertTo(DosingDecisionData.InsulinOnBoard::class, mapFunctionName = "toDomain") data class InsulinOnBoardDto( @Contextual @SerialName("time") val time: Instant? = null, @SerialName("amount") val amount: Double = -1.0, - ) { - - @KonvertFrom(DosingDecisionData.InsulinOnBoard::class, mapFunctionName = "fromDomain") - companion object {} - } + ) @Serializable - @KonvertTo(DosingDecisionData.RecommendedBasal::class, mapFunctionName = "toDomain") data class RecommendedBasalDto( @SerialName("rate") val rate: Double = -1.0, @SerialName("duration") val duration: Double? = null, - ) { - - @KonvertFrom(DosingDecisionData.RecommendedBasal::class, mapFunctionName = "fromDomain") - companion object {} - } + ) @Serializable - @KonvertTo(DosingDecisionData.RecommendedBolus::class, mapFunctionName = "toDomain") data class RecommendedBolusDto( @SerialName("amount") val amount: Double = -1.0, - ) { - - @KonvertFrom(DosingDecisionData.RecommendedBolus::class, mapFunctionName = "fromDomain") - companion object {} - } + ) @Serializable - @KonvertTo(DosingDecisionData.RequestedBolus::class, mapFunctionName = "toDomain") data class RequestedBolusDto( @SerialName("amount") val amount: Double = -1.0, - ) { - - @KonvertFrom(DosingDecisionData.RequestedBolus::class, mapFunctionName = "fromDomain") - companion object {} - } + ) @Serializable - @KonvertTo(DosingDecisionData.Units::class, mapFunctionName = "toDomain") data class UnitsDto( @SerialName("bg") val bg: BloodGlucoseDto.UnitsDto = BloodGlucoseDto.UnitsDto.MilligramsPerDeciliter, @@ -147,10 +117,6 @@ data class DosingDecisionDataDto( @SerialName("insulin") val insulin: InsulinDto = InsulinDto.Units, ) { - - @KonvertFrom(DosingDecisionData.Units::class, mapFunctionName = "fromDomain") - companion object {} - @Serializable enum class CarbDto { @@ -164,19 +130,19 @@ data class DosingDecisionDataDto( @Serializable enum class InsulinDto { - @SerialName("units") + @SerialName("Units") Units, } } } -internal fun DosingDecisionDataDto.UnitsDto.InsulinDto.toDomain() = when (this) { - DosingDecisionDataDto.UnitsDto.InsulinDto.Units -> DosingDecisionData.Units.Insulin.Units +internal fun UnitsDto.InsulinDto.toDomain() = when (this) { + UnitsDto.InsulinDto.Units -> DosingDecisionData.Units.Insulin.Units } -internal fun DosingDecisionDataDto.UnitsDto.CarbDto.toDomain() = when (this) { - DosingDecisionDataDto.UnitsDto.CarbDto.Exchanges -> DosingDecisionData.Units.Carb.Exchanges - DosingDecisionDataDto.UnitsDto.CarbDto.Grams -> DosingDecisionData.Units.Carb.Grams +internal fun UnitsDto.CarbDto.toDomain() = when (this) { + UnitsDto.CarbDto.Exchanges -> DosingDecisionData.Units.Carb.Exchanges + UnitsDto.CarbDto.Grams -> DosingDecisionData.Units.Carb.Grams } internal fun BloodGlucoseDto.UnitsDto.toDomain() = when (this) { @@ -185,15 +151,107 @@ internal fun BloodGlucoseDto.UnitsDto.toDomain() = when (this) { } internal fun DosingDecisionData.Units.Insulin.toDto() = when (this) { - DosingDecisionData.Units.Insulin.Units -> DosingDecisionDataDto.UnitsDto.InsulinDto.Units + DosingDecisionData.Units.Insulin.Units -> UnitsDto.InsulinDto.Units } internal fun DosingDecisionData.Units.Carb.toDto() = when (this) { - DosingDecisionData.Units.Carb.Exchanges -> DosingDecisionDataDto.UnitsDto.CarbDto.Exchanges - DosingDecisionData.Units.Carb.Grams -> DosingDecisionDataDto.UnitsDto.CarbDto.Grams + DosingDecisionData.Units.Carb.Exchanges -> UnitsDto.CarbDto.Exchanges + DosingDecisionData.Units.Carb.Grams -> UnitsDto.CarbDto.Grams } internal fun BloodGlucose.Units.toDto() = when (this) { BloodGlucose.Units.MilligramsPerDeciliter -> BloodGlucoseDto.UnitsDto.MilligramsPerDeciliter BloodGlucose.Units.MillimolesPerLiter -> BloodGlucoseDto.UnitsDto.MillimolesPerLiter -} \ No newline at end of file +} + +fun CarbsOnBoardDto.toDomain() = DosingDecisionData.CarbsOnBoard( + time = time, + amount = amount, +) + +fun DosingDecisionData.CarbsOnBoard.toDto() = CarbsOnBoardDto( + time = time, + amount = amount, +) + +fun DosingDecisionDataDto.toDomain(): DosingDecisionData = DosingDecisionData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + reason = reason, + carbsOnBoard = carbsOnBoard?.toDomain(), + insulinOnBoard = insulinOnBoard?.toDomain(), + recommendedBasal = recommendedBasal?.toDomain(), + recommendedBolus = recommendedBolus?.toDomain(), + requestedBolus = requestedBolus?.toDomain(), + scheduleTimeZoneOffset = scheduleTimeZoneOffset, + units = units.toDomain(), +) + +fun DosingDecisionData.toDto(): DosingDecisionDataDto = DosingDecisionDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + reason = reason, + carbsOnBoard = carbsOnBoard?.toDto(), + insulinOnBoard = insulinOnBoard?.toDto(), + recommendedBasal = recommendedBasal?.toDto(), + recommendedBolus = recommendedBolus?.toDto(), + requestedBolus = requestedBolus?.toDto(), + scheduleTimeZoneOffset = scheduleTimeZoneOffset, + units = units.toDto(), +) + +fun InsulinOnBoardDto.toDomain() = DosingDecisionData.InsulinOnBoard( + time = time, + amount = amount, +) + +fun DosingDecisionData.InsulinOnBoard.toDto() = InsulinOnBoardDto( + time = time, + amount = amount, +) + +fun RecommendedBasalDto.toDomain() = DosingDecisionData.RecommendedBasal( + rate = rate, + duration = duration, +) + +fun DosingDecisionData.RecommendedBasal.toDto() = RecommendedBasalDto( + rate = rate, + duration = duration, +) + +fun RecommendedBolusDto.toDomain() = DosingDecisionData.RecommendedBolus( + amount = amount, +) + +fun DosingDecisionData.RecommendedBolus.toDto() = RecommendedBolusDto( + amount = amount, +) + +fun RequestedBolusDto.toDomain() = DosingDecisionData.RequestedBolus( + amount = amount +) + +fun DosingDecisionData.RequestedBolus.toDto() = RequestedBolusDto( + amount = amount +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/FoodDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/FoodDataDto.kt similarity index 51% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/FoodDataDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/FoodDataDto.kt index 24c90be..84adc6f 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/FoodDataDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/FoodDataDto.kt @@ -1,12 +1,11 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.dto.AssociationDto -import org.tidepool.sdk.model.data.BasalAutomatedData +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto import org.tidepool.sdk.model.data.FoodData import java.time.Instant import java.util.TimeZone @@ -14,7 +13,6 @@ import kotlin.time.Duration // schema food.v1 @Serializable -@KonvertTo(FoodData::class, mapFunctionName = "toDomain") data class FoodDataDto( override val id: String = "", override val type: DataTypeDto = DataTypeDto.Alert, @@ -32,7 +30,7 @@ data class FoodDataDto( @Contextual override val timeZone: TimeZone? = null, @Contextual - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, @SerialName("brand") val brand: String? = null, @@ -46,9 +44,6 @@ data class FoodDataDto( val name: String? = null, ) : BaseDataDto() { - @KonvertFrom(FoodData::class, mapFunctionName = "fromDomain") - companion object {} - val amount: Nothing get() = TODO("schema \"amount.v1\" not implemented") val ingredients: Nothing @@ -74,4 +69,60 @@ data class FoodDataDto( @SerialName("other") Other, } +} + +fun FoodDataDto.toDomain(): FoodData = FoodData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + brand = brand, + code = code, + meal = meal?.toDomain(), + mealOther = mealOther, + name = name, +) + +fun FoodData.toDto(): FoodDataDto = FoodDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + brand = brand, + code = code, + meal = meal?.toDto(), + mealOther = mealOther, + name = name, +) + +private fun FoodDataDto.MealDto.toDomain(): FoodData.Meal = when (this) { + FoodDataDto.MealDto.Breakfast -> FoodData.Meal.Breakfast + FoodDataDto.MealDto.Lunch -> FoodData.Meal.Lunch + FoodDataDto.MealDto.Dinner -> FoodData.Meal.Dinner + FoodDataDto.MealDto.Snack -> FoodData.Meal.Snack + FoodDataDto.MealDto.Other -> FoodData.Meal.Other +} + +private fun FoodData.Meal.toDto(): FoodDataDto.MealDto = when (this) { + FoodData.Meal.Breakfast -> FoodDataDto.MealDto.Breakfast + FoodData.Meal.Lunch -> FoodDataDto.MealDto.Lunch + FoodData.Meal.Dinner -> FoodDataDto.MealDto.Dinner + FoodData.Meal.Snack -> FoodDataDto.MealDto.Snack + FoodData.Meal.Other -> FoodDataDto.MealDto.Other } \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/InsulinDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/InsulinDataDto.kt similarity index 54% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/InsulinDataDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/InsulinDataDto.kt index 25ede7e..91041c9 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/InsulinDataDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/InsulinDataDto.kt @@ -1,12 +1,11 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable import kotlinx.serialization.SerialName import org.tidepool.sdk.dto.AssociationDto -import org.tidepool.sdk.model.data.BasalAutomatedData +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto import org.tidepool.sdk.model.data.InsulinData import java.time.Instant import java.util.TimeZone @@ -14,7 +13,6 @@ import kotlin.time.Duration // schema insulin.v1 @Serializable -@KonvertTo(InsulinData::class, mapFunctionName = "toDomain") data class InsulinDataDto( override val id: String = "", override val type: DataTypeDto = DataTypeDto.Alert, @@ -32,7 +30,7 @@ data class InsulinDataDto( @Contextual override val timeZone: TimeZone? = null, @Contextual - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, @SerialName("dose") val dose: DoseDto, @@ -40,9 +38,40 @@ data class InsulinDataDto( val site: String? ) : BaseDataDto() { - @KonvertFrom(InsulinData::class, mapFunctionName = "fromDomain") - companion object {} - val formulation: Nothing get() = TODO("schema \"formulation.v1\" not implemented") -} \ No newline at end of file +} + +fun InsulinDataDto.toDomain(): InsulinData = InsulinData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + dose = dose.toDomain(), + site = site, +) + +fun InsulinData.toDto(): InsulinDataDto = InsulinDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, + dose = dose.toDto(), + site = site, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/InsulinDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/InsulinDto.kt similarity index 56% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/InsulinDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/InsulinDto.kt index 75fad15..70a2fab 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/InsulinDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/InsulinDto.kt @@ -1,11 +1,9 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.data.BasalAutomatedData import org.tidepool.sdk.model.data.Dose +import org.tidepool.sdk.model.data.Insulin @Serializable class InsulinDto { @@ -20,7 +18,6 @@ class InsulinDto { // schema dose.v1 @Serializable -@KonvertTo(Dose::class, mapFunctionName = "toDomain") data class DoseDto( @SerialName("units") val units: InsulinDto.UnitsDto, @@ -32,7 +29,24 @@ data class DoseDto( val correction: Double?, @SerialName("active") val active: Double?, -) { - @KonvertFrom(Dose::class, mapFunctionName = "fromDomain") - companion object {} -} +) + +fun DoseDto.toDomain(): Dose = Dose( + units = when (units) { + InsulinDto.UnitsDto.Units -> Insulin.Units.Units + }, + total = total, + food = food, + correction = correction, + active = active +) + +fun Dose.toDto(): DoseDto = DoseDto( + units = when (units) { + Insulin.Units.Units -> InsulinDto.UnitsDto.Units + }, + total = total, + food = food, + correction = correction, + active = active +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/NewDataSetDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/NewDataSetDto.kt similarity index 62% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/NewDataSetDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/NewDataSetDto.kt index 86e7ee3..d97b1ce 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/NewDataSetDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/NewDataSetDto.kt @@ -1,18 +1,18 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.data.DosingDecisionData import org.tidepool.sdk.model.data.NewDataSet import java.time.Instant import kotlin.time.Duration @Serializable -@KonvertTo(NewDataSet::class, mapFunctionName = "toDomain") data class NewDataSetDto( + @SerialName("id") + val id: String? = null, + @SerialName("type") + val type: String? = "upload", @SerialName("client") val client: ClientSoftwareDto? = null, @SerialName("dataSetType") @@ -26,7 +26,7 @@ data class NewDataSetDto( @SerialName("deviceSerialNumber") val deviceSerialNumber: String? = null, @SerialName("deviceTags") - val deviceTags: List? = null, + val deviceTags: List? = null, @SerialName("deduplicator") val deduplicator: DeduplicatorDescriptorDto? = null, @SerialName("time") @@ -36,8 +36,20 @@ data class NewDataSetDto( @SerialName("timezone") val timezone: String? = null, @SerialName("timezoneOffset") - @Contextual val timezoneOffset: Duration? = null -) { - @KonvertFrom(NewDataSet::class, mapFunctionName = "fromDomain") - companion object {} -} \ No newline at end of file + val timeZoneOffset: Int? = null, +) + +fun NewDataSet.toDto(): NewDataSetDto = NewDataSetDto( + client = client?.toDto(), + dataSetType = dataSetType, + deviceId = deviceId, + deviceManufacturers = deviceManufacturers, + deviceModel = deviceModel, + deviceSerialNumber = deviceSerialNumber, + deviceTags = deviceTags?.map { it.toDto() }, + deduplicator = deduplicator?.toDto(), + time = time, + timeProcessing = timeProcessing, + timezone = timezone, + timeZoneOffset = timeZoneOffset, +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/NewDataSourceDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/NewDataSourceDto.kt similarity index 54% rename from data/src/main/kotlin/org/tidepool/sdk/dto/data/NewDataSourceDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/NewDataSourceDto.kt index e6cb045..e44ce0b 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/NewDataSourceDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/NewDataSourceDto.kt @@ -1,13 +1,10 @@ package org.tidepool.sdk.dto.data -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.data.NewDataSource @Serializable -@KonvertTo(NewDataSource::class, mapFunctionName = "toDomain") data class NewDataSourceDto( @SerialName("providerName") val providerName: String? = null, @@ -15,7 +12,16 @@ data class NewDataSourceDto( val providerSessionId: String? = null, @SerialName("providerType") val providerType: String? = null -) { - @KonvertFrom(NewDataSource::class, mapFunctionName = "fromDomain") - companion object {} -} \ No newline at end of file +) + +fun NewDataSourceDto.toDomain(): NewDataSource = NewDataSource( + providerName = providerName, + providerSessionId = providerSessionId, + providerType = providerType, +) + +fun NewDataSource.toDto(): NewDataSourceDto = NewDataSourceDto( + providerName = providerName, + providerSessionId = providerSessionId, + providerType = providerType, +) \ No newline at end of file diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/PumpSettingsDataDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/PumpSettingsDataDto.kt new file mode 100644 index 0000000..28e789f --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/data/PumpSettingsDataDto.kt @@ -0,0 +1,62 @@ +package org.tidepool.sdk.dto.data + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import org.tidepool.sdk.dto.AssociationDto +import org.tidepool.sdk.dto.toDomain +import org.tidepool.sdk.dto.toDto +import org.tidepool.sdk.model.data.PumpSettingsData +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +@Serializable +data class PumpSettingsDataDto( + override val id: String = "", + override val type: BaseDataDto.DataTypeDto = BaseDataDto.DataTypeDto.PumpSettings, + @Contextual + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + @Contextual + override val clockDriftOffset: Duration? = null, + @Contextual + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + @Contextual + override val timeZone: TimeZone? = null, + @Contextual + override val timeZoneOffset: Int? = null, +) : BaseDataDto() + +fun PumpSettingsDataDto.toDomain(): PumpSettingsData = PumpSettingsData( + id = id, + type = type.toDomain(), + time = time, + annotations = annotations, + associations = associations.map { it.toDomain() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) + +fun PumpSettingsData.toDto(): PumpSettingsDataDto = PumpSettingsDataDto( + id = id, + type = type.toDto(), + time = time, + annotations = annotations, + associations = associations.map { it.toDto() }, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/general/MinimumClientVersionsDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/general/MinimumClientVersionsDto.kt similarity index 63% rename from data/src/main/kotlin/org/tidepool/sdk/dto/general/MinimumClientVersionsDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/general/MinimumClientVersionsDto.kt index 522566b..146c521 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/general/MinimumClientVersionsDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/general/MinimumClientVersionsDto.kt @@ -1,20 +1,25 @@ package org.tidepool.sdk.dto.general -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.general.MinimumClientVersions @Serializable -@KonvertTo(MinimumClientVersions::class, mapFunctionName = "toDomain") data class MinimumClientVersionsDto( @SerialName("minimumClientVersions") val versions: VersionsDto ) { @Serializable - @KonvertTo(MinimumClientVersions.Versions::class, mapFunctionName = "toDomain") data class VersionsDto( val uploaderMinimum: String ) -} \ No newline at end of file +} + +fun MinimumClientVersionsDto.toDomain() = MinimumClientVersions( + versions = versions.toDomain(), +) + +fun MinimumClientVersionsDto.VersionsDto.toDomain() = MinimumClientVersions.Versions( + uploaderMinimum = uploaderMinimum, +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/message/EditMessageDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/EditMessageDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/message/EditMessageDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/EditMessageDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/message/MessageDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/MessageDto.kt similarity index 69% rename from data/src/main/kotlin/org/tidepool/sdk/dto/message/MessageDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/MessageDto.kt index acff8d0..34dd235 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/message/MessageDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/MessageDto.kt @@ -1,6 +1,5 @@ package org.tidepool.sdk.dto.message -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -8,14 +7,12 @@ import org.tidepool.sdk.model.messages.Message import java.time.Instant @Serializable -@KonvertTo(Message::class, mapFunctionName = "toDomain") data class MessageDto( @SerialName("message") val message: MessageContentDto = MessageContentDto() ) { @Serializable - @KonvertTo(Message::class, mapFunctionName = "toDomain") data class MessageContentDto( @SerialName("id") val id: String = "", @@ -44,4 +41,27 @@ data class MessageDto( @SerialName("fullName") val fullName: String = "", ) -} \ No newline at end of file +} + +fun MessageDto.toDomain(): Message = Message( + id = message.id, + guid = message.guid, + userId = message.userId, + groupId = message.groupId, + timestamp = message.timestamp, + createdTime = message.createdTime, + modifiedTime = message.modifiedTime, + messageText = message.messageText, +) + +fun MessageDto.MessageContentDto + .toDomain(): Message = Message( + id = id, + guid = guid, + userId = userId, + groupId = groupId, + timestamp = timestamp, + createdTime = createdTime, + modifiedTime = modifiedTime, + messageText = messageText, +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/message/MessageListDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/MessageListDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/message/MessageListDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/MessageListDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/message/MessageResponseDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/MessageResponseDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/message/MessageResponseDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/MessageResponseDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/message/NewMessageDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/NewMessageDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/message/NewMessageDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/message/NewMessageDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/CollectionDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/CollectionDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/CollectionDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/CollectionDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/PreferencesDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/PreferencesDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/PreferencesDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/PreferencesDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/PrivateDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/PrivateDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/PrivateDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/PrivateDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/SettingsDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/SettingsDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/SettingsDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/SettingsDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/UserProfileDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/UserProfileDto.kt similarity index 82% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/UserProfileDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/UserProfileDto.kt index 63eeb90..e18f54b 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/UserProfileDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/UserProfileDto.kt @@ -1,7 +1,5 @@ package org.tidepool.sdk.dto.metadata -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.metadata.ClinicianProfile @@ -9,18 +7,14 @@ import org.tidepool.sdk.model.metadata.PatientProfile import org.tidepool.sdk.model.metadata.UserProfile @Serializable -@KonvertTo(UserProfile::class, mapFunctionName = "toDomain") data class UserProfileDto( @SerialName("fullName") val fullName: String? = null, @SerialName("patient") val patient: PatientDataDto? = null, ) { - @KonvertFrom(UserProfile::class, mapFunctionName = "fromDomain") - companion object {} - + @Serializable - @KonvertTo(UserProfile.PatientData::class, mapFunctionName = "toDomain") data class PatientDataDto( @SerialName("diagnosisType") val diagnosisType: DiagnosisTypeDto? = null, @@ -40,11 +34,7 @@ data class UserProfileDto( val email: String? = null, @SerialName("mrn") val mrn: String? = null, - ) { - @KonvertFrom(UserProfile.PatientData::class, mapFunctionName = "fromDomain") - companion object {} - } - + ) @Serializable enum class DiagnosisTypeDto { @@ -84,7 +74,6 @@ data class UserProfileDto( } @Serializable -@KonvertTo(ClinicianProfile::class, mapFunctionName = "toDomain") data class ClinicianProfileDto( @SerialName("fullName") val fullName: String? = null, @@ -93,7 +82,6 @@ data class ClinicianProfileDto( ) { @Serializable - @KonvertTo(ClinicianProfile.ClinicData::class, mapFunctionName = "toDomain") data class ClinicDataDto( @SerialName("name") val name: String? = null, @@ -130,7 +118,6 @@ data class ClinicianProfileDto( } @Serializable -@KonvertTo(PatientProfile::class, mapFunctionName = "toDomain") data class PatientProfileDto( @SerialName("fullName") val fullName: String? = null, @@ -141,7 +128,6 @@ data class PatientProfileDto( ) { @Serializable - @KonvertTo(PatientProfile.PatientData::class, mapFunctionName = "toDomain") data class PatientDataDto( @SerialName("birthday") val birthday: String? = null, @@ -210,4 +196,63 @@ internal fun ClinicianProfileDto.ClinicianRoleDto.toDomain() = when (this) { ClinicianProfileDto.ClinicianRoleDto.PrimaryCarePhysician -> ClinicianProfile.ClinicianRole.PrimaryCarePhysician ClinicianProfileDto.ClinicianRoleDto.PhysicianAssistant -> ClinicianProfile.ClinicianRole.PhysicianAssistant ClinicianProfileDto.ClinicianRoleDto.Other -> ClinicianProfile.ClinicianRole.Other -} \ No newline at end of file +} + +fun ClinicianProfileDto.ClinicDataDto.toDomain() = ClinicianProfile.ClinicData( + name = name, + role = role?.toDomain(), + telephone = telephone, +) + +fun ClinicianProfileDto.toDomain(): ClinicianProfile = ClinicianProfile( + fullName = fullName, + clinic = clinic?.toDomain(), +) + +fun UserProfileDto.PatientDataDto.toDomain(): UserProfile.PatientData = UserProfile.PatientData( + diagnosisType = diagnosisType?.toDomain(), + diagnosisDate = diagnosisDate, + birthday = birthday, + biologicalSex = biologicalSex?.toDomain(), + targetDevices = targetDevices, + targetTimezone = targetTimezone, + about = about, + email = email, + mrn = mrn, +) + +fun PatientProfileDto.PatientDataDto.toDomain(): PatientProfile.PatientData = PatientProfile.PatientData( + birthday = birthday, + email = email, + mrn = mrn, + targetDevices = targetDevices, + targetTimezone = targetTimezone, +) + +fun UserProfile.PatientData.toDto(): UserProfileDto.PatientDataDto = UserProfileDto.PatientDataDto( + diagnosisType = diagnosisType?.toDto(), + diagnosisDate = diagnosisDate, + birthday = birthday, + biologicalSex = biologicalSex?.toDto(), + targetDevices = targetDevices, + targetTimezone = targetTimezone, + about = about, + email = email, + mrn = mrn, +) + +fun PatientProfileDto.toDomain(): PatientProfile = PatientProfile( + fullName = fullName, + patient = patient?.toDomain(), + emails = emails +) + +fun UserProfileDto.toDomain(): UserProfile = UserProfile( + fullName = fullName, + patient = patient?.toDomain(), +) + +fun UserProfile.toDto(): UserProfileDto = UserProfileDto( + fullName = fullName, + patient = patient?.toDto(), +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/users/PermissionsDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/users/PermissionsDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/users/PermissionsDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/users/PermissionsDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/users/TrustUserDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/users/TrustUserDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/users/TrustUserDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/users/TrustUserDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/metadata/users/UserDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/users/UserDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/metadata/users/UserDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/metadata/users/UserDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/prescription/NewPrescriptionDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/NewPrescriptionDto.kt similarity index 70% rename from data/src/main/kotlin/org/tidepool/sdk/dto/prescription/NewPrescriptionDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/NewPrescriptionDto.kt index e41c9bb..2bf444b 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/prescription/NewPrescriptionDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/NewPrescriptionDto.kt @@ -1,6 +1,5 @@ package org.tidepool.sdk.dto.prescription -import io.mcarle.konvert.api.KonvertFrom import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.prescription.NewPrescription @@ -25,7 +24,16 @@ data class NewPrescriptionDto( val endDate: String? = null, @SerialName("notes") val notes: String? = null, -) { - @KonvertFrom(NewPrescription::class, mapFunctionName = "fromDomain") - companion object {} -} \ No newline at end of file +) + +fun NewPrescription.toDto(): NewPrescriptionDto = NewPrescriptionDto( + clinicId = clinicId, + patientId = patientId, + medicationName = medicationName, + dosage = dosage, + frequency = frequency, + instructions = instructions, + startDate = startDate, + endDate = endDate, + notes = notes, +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionStatusDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionStatusDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionStatusDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/PrescriptionStatusDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/prescription/UpdatePrescriptionDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/UpdatePrescriptionDto.kt similarity index 71% rename from data/src/main/kotlin/org/tidepool/sdk/dto/prescription/UpdatePrescriptionDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/UpdatePrescriptionDto.kt index 2ee5122..8e45071 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/prescription/UpdatePrescriptionDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/prescription/UpdatePrescriptionDto.kt @@ -1,6 +1,5 @@ package org.tidepool.sdk.dto.prescription -import io.mcarle.konvert.api.KonvertFrom import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.prescription.UpdatePrescription @@ -23,7 +22,15 @@ data class UpdatePrescriptionDto( val status: PrescriptionStatusDto? = null, @SerialName("notes") val notes: String? = null, -) { - @KonvertFrom(UpdatePrescription::class, mapFunctionName = "fromDomain") - companion object {} -} \ No newline at end of file +) + +fun UpdatePrescription.toDto(): UpdatePrescriptionDto = UpdatePrescriptionDto( + medicationName = medicationName, + dosage = dosage, + frequency = frequency, + instructions = instructions, + startDate = startDate, + endDate = endDate, + status = status?.toDto(), + notes = notes, +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/ContinuousPeriodDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/ContinuousPeriodDto.kt similarity index 81% rename from data/src/main/kotlin/org/tidepool/sdk/dto/summary/ContinuousPeriodDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/ContinuousPeriodDto.kt index 096c9c4..3d5c787 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/ContinuousPeriodDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/ContinuousPeriodDto.kt @@ -1,10 +1,8 @@ package org.tidepool.sdk.dto.summary -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.summary.ContinuousPeriod -import org.tidepool.sdk.model.summary.GlucosePeriod @Serializable data class ContinuousRangesDto( @@ -17,7 +15,6 @@ data class ContinuousRangesDto( ) @Serializable -@KonvertTo(ContinuousPeriod::class, mapFunctionName = "toDomain") data class ContinuousPeriodDto( @SerialName("realtime") val realtime: GlucoseRangeDto, diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/GlucosePeriodDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/GlucosePeriodDto.kt similarity index 65% rename from data/src/main/kotlin/org/tidepool/sdk/dto/summary/GlucosePeriodDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/GlucosePeriodDto.kt index ce8eb0f..985750a 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/GlucosePeriodDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/GlucosePeriodDto.kt @@ -1,13 +1,11 @@ package org.tidepool.sdk.dto.summary -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.summary.GlucosePeriod import org.tidepool.sdk.model.summary.GlucosePeriodDelta @Serializable -@KonvertTo(GlucosePeriod::class, mapFunctionName = "toDomain") data class GlucosePeriodDto( // From GlucoseRanges @SerialName("total") @@ -59,7 +57,6 @@ data class GlucosePeriodDto( ) @Serializable -@KonvertTo(GlucosePeriodDelta::class, mapFunctionName = "toDomain") data class GlucosePeriodDeltaDto( // From GlucoseRanges @SerialName("total") @@ -106,4 +103,51 @@ data class GlucosePeriodDeltaDto( val standardDeviation: Double, @SerialName("averageDailyRecords") val averageDailyRecords: Double -) \ No newline at end of file +) + +fun GlucosePeriodDeltaDto.toDomain(): GlucosePeriodDelta = GlucosePeriodDelta( + total = total.toDomain(), + inVeryLow = inVeryLow.toDomain(), + inLow = inLow.toDomain(), + inTarget = inTarget.toDomain(), + inHigh = inHigh.toDomain(), + inVeryHigh = inVeryHigh.toDomain(), + inExtremeHigh = inExtremeHigh.toDomain(), + inAnyLow = inAnyLow.toDomain(), + inAnyHigh = inAnyHigh.toDomain(), + min = min, + minDelta = minDelta, + max = max, + maxDelta = maxDelta, + hoursWithData = hoursWithData, + daysWithData = daysWithData, + averageGlucoseMmol = averageGlucoseMmol, + glucoseManagementIndicator = glucoseManagementIndicator, + coefficientOfVariation = coefficientOfVariation, + standardDeviation = standardDeviation, + averageDailyRecords = averageDailyRecords +) + +fun GlucosePeriodDto.toDomain(): GlucosePeriod = GlucosePeriod( + total = total.toDomain(), + inVeryLow = inVeryLow.toDomain(), + inLow = inLow.toDomain(), + inTarget = inTarget.toDomain(), + inHigh = inHigh.toDomain(), + inVeryHigh = inVeryHigh.toDomain(), + inExtremeHigh = inExtremeHigh.toDomain(), + inAnyLow = inAnyLow.toDomain(), + inAnyHigh = inAnyHigh.toDomain(), + min = min, + minDelta = minDelta, + max = max, + maxDelta = maxDelta, + hoursWithData = hoursWithData, + daysWithData = daysWithData, + averageGlucoseMmol = averageGlucoseMmol, + glucoseManagementIndicator = glucoseManagementIndicator, + coefficientOfVariation = coefficientOfVariation, + standardDeviation = standardDeviation, + averageDailyRecords = averageDailyRecords, + delta = delta?.toDomain() +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/GlucoseRangeDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/GlucoseRangeDto.kt similarity index 76% rename from data/src/main/kotlin/org/tidepool/sdk/dto/summary/GlucoseRangeDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/GlucoseRangeDto.kt index 0a0cee7..5b7353d 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/GlucoseRangeDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/GlucoseRangeDto.kt @@ -1,13 +1,11 @@ package org.tidepool.sdk.dto.summary -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.summary.GlucosePeriod import org.tidepool.sdk.model.summary.GlucoseRange @Serializable -@KonvertTo(GlucoseRange::class, mapFunctionName = "toDomain") data class GlucoseRangeDto( @SerialName("glucose") val glucose: Double, @@ -26,5 +24,13 @@ internal fun GlucoseRange.toDto(): GlucoseRangeDto = GlucoseRangeDto( minutes = minutes, records = records, percent = percent, - variance = variance + variance = variance, +) + +fun GlucoseRangeDto.toDomain(): GlucoseRange = GlucoseRange( + glucose = glucose, + minutes = minutes, + records = records, + percent = percent, + variance = variance, ) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryConfigDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryConfigDto.kt similarity index 65% rename from data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryConfigDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryConfigDto.kt index d178c3d..1d91815 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryConfigDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryConfigDto.kt @@ -1,12 +1,10 @@ package org.tidepool.sdk.dto.summary -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.tidepool.sdk.model.summary.SummaryConfig @Serializable -@KonvertTo(SummaryConfig::class, mapFunctionName = "toDomain") data class SummaryConfigDto( @SerialName("schemaVersion") val schemaVersion: Int, @@ -18,4 +16,12 @@ data class SummaryConfigDto( val lowGlucoseThreshold: Double, @SerialName("VeryLowGlucoseThreshold") val veryLowGlucoseThreshold: Double, -) \ No newline at end of file +) + +fun SummaryConfigDto.toDomain(): SummaryConfig = SummaryConfig( + schemaVersion = schemaVersion, + highGlucoseThreshold = highGlucoseThreshold, + veryHighGlucoseThreshold = veryHighGlucoseThreshold, + lowGlucoseThreshold = lowGlucoseThreshold, + veryLowGlucoseThreshold = veryLowGlucoseThreshold +) diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryDatesDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryDatesDto.kt similarity index 73% rename from data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryDatesDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryDatesDto.kt index a105752..15c8874 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryDatesDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryDatesDto.kt @@ -1,6 +1,5 @@ package org.tidepool.sdk.dto.summary -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -8,7 +7,6 @@ import org.tidepool.sdk.model.summary.SummaryDates import java.time.Instant @Serializable -@KonvertTo(SummaryDates::class, mapFunctionName = "toDomain") data class SummaryDatesDto( @SerialName("lastUpdatedDate") @Contextual @@ -29,4 +27,14 @@ data class SummaryDatesDto( val outdatedSince: Instant? = null, @SerialName("outdatedReason") val outdatedReason: List = emptyList(), +) + +fun SummaryDatesDto.toDomain(): SummaryDates = SummaryDates( + lastUpdatedDate = lastUpdatedDate, + lastUpdatedReason = lastUpdatedReason, + firstData = firstData, + lastData = lastData, + lastUploadDate = lastUploadDate, + outdatedSince = outdatedSince, + outdatedReason = outdatedReason, ) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryDto.kt similarity index 69% rename from data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryDto.kt index 138df11..824aeda 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryDto.kt @@ -1,11 +1,11 @@ package org.tidepool.sdk.dto.summary -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonClassDiscriminator -import org.tidepool.sdk.model.summary.CgmSummary import org.tidepool.sdk.model.summary.BgmSummary +import org.tidepool.sdk.model.summary.CgmSummary +import org.tidepool.sdk.model.summary.ContinuousPeriod import org.tidepool.sdk.model.summary.ContinuousSummary import org.tidepool.sdk.model.summary.Summary @@ -21,7 +21,6 @@ sealed class SummaryDto { @Serializable @SerialName("cgm") -@KonvertTo(CgmSummary::class, mapFunctionName = "toDomain") data class CgmSummaryDto( @SerialName("id") override val id: String, @@ -39,7 +38,6 @@ data class CgmSummaryDto( @Serializable @SerialName("bgm") -@KonvertTo(BgmSummary::class, mapFunctionName = "toDomain") data class BgmSummaryDto( @SerialName("id") override val id: String, @@ -57,7 +55,6 @@ data class BgmSummaryDto( @Serializable @SerialName("con") -@KonvertTo(ContinuousSummary::class, mapFunctionName = "toDomain") data class ContinuousSummaryDto( @SerialName("id") override val id: String, @@ -77,4 +74,35 @@ fun SummaryDto.toDomain(): Summary = when (this) { is CgmSummaryDto -> toDomain() is BgmSummaryDto -> toDomain() is ContinuousSummaryDto -> toDomain() -} \ No newline at end of file +} + +fun BgmSummaryDto.toDomain(): BgmSummary = BgmSummary( + id = id, + userId = userId, + config = config.toDomain(), + dates = dates.toDomain(), + periods = periods.mapValues { (_, it) -> it.toDomain() } +) + +fun CgmSummaryDto.toDomain(): CgmSummary = CgmSummary( + id = id, + userId = userId, + config = config.toDomain(), + dates = dates.toDomain(), + periods = periods.mapValues { (_, it) -> it.toDomain() } +) + +fun ContinuousPeriodDto.toDomain(): ContinuousPeriod = ContinuousPeriod( + realtime = realtime.toDomain(), + deferred = deferred.toDomain(), + total = total.toDomain(), + averageDailyRecords = averageDailyRecords +) + +fun ContinuousSummaryDto.toDomain(): ContinuousSummary = ContinuousSummary( + id = id, + userId = userId, + config = config.toDomain(), + dates = dates.toDomain(), + periods = periods.mapValues { (_, it) -> it.toDomain() } +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryTypeDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryTypeDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/summary/SummaryTypeDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/summary/SummaryTypeDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/task/NewTaskDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/NewTaskDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/task/NewTaskDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/NewTaskDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/task/TaskDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/TaskDto.kt similarity index 96% rename from data/src/main/kotlin/org/tidepool/sdk/dto/task/TaskDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/TaskDto.kt index 86f8706..a9bfbfd 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/task/TaskDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/TaskDto.kt @@ -1,7 +1,5 @@ package org.tidepool.sdk.dto.task -import io.mcarle.konvert.api.KonvertTo -import io.mcarle.konvert.api.Mapping import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonObject diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/task/TaskStateDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/TaskStateDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/task/TaskStateDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/TaskStateDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/task/UpdateTaskDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/UpdateTaskDto.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/dto/task/UpdateTaskDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/task/UpdateTaskDto.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/user/UserDto.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/user/UserDto.kt similarity index 73% rename from data/src/main/kotlin/org/tidepool/sdk/dto/user/UserDto.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/dto/user/UserDto.kt index d0ad619..5e1c27c 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/user/UserDto.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/dto/user/UserDto.kt @@ -1,15 +1,14 @@ package org.tidepool.sdk.dto.user -import io.mcarle.konvert.api.KonvertTo import kotlinx.serialization.Serializable import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import org.tidepool.sdk.model.metadata.users.User import org.tidepool.sdk.dto.metadata.UserProfileDto +import org.tidepool.sdk.dto.metadata.toDomain import java.time.Instant @Serializable -@KonvertTo(User::class, mapFunctionName = "toDomain") open class UserDto( @SerialName("emailVerified") val emailVerified: Boolean = false, @@ -42,3 +41,18 @@ open class UserDto( @SerialName("profile") val profile: UserProfileDto? = null, ) + +fun UserDto.toDomain(): User = User( + emailVerified = emailVerified, + emails = emails, + termsAccepted = termsAccepted, + userId = userId, + roles = roles, + createdTime = createdTime, + createdUserId = createdUserId, + modifiedTime = modifiedTime, + modifiedUserId = modifiedUserId, + deletedTime = deletedTime, + deletedUserId = deletedUserId, + profile = profile?.toDomain(), +) \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/AlertRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/AlertRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/AlertRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/AlertRepositoryImpl.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/AuthorizationRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/AuthorizationRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/AuthorizationRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/AuthorizationRepositoryImpl.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/BlobRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/BlobRepositoryImpl.kt similarity index 73% rename from data/src/main/kotlin/org/tidepool/sdk/repository/BlobRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/BlobRepositoryImpl.kt index 3c535b0..1b261a1 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/repository/BlobRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/BlobRepositoryImpl.kt @@ -1,7 +1,5 @@ package org.tidepool.sdk.repository -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.RequestBody.Companion.toRequestBody import org.tidepool.sdk.api.BlobApi import org.tidepool.sdk.dto.blob.BlobStatusDto import org.tidepool.sdk.dto.blob.DeviceLogContentDto @@ -31,22 +29,22 @@ class BlobRepositoryImpl( ) }.mapList { it.toDomain() } - override suspend fun createBlob( - userId: String, - contentType: String, - digest: String, - content: ByteArray, - sessionToken: String - ) = runCatchingNetworkExceptions { - val requestBody = content.toRequestBody(contentType.toMediaType()) - blobApi.createBlob( - sessionToken = sessionToken, - userId = userId, - contentType = contentType, - digest = digest, - content = requestBody, - ) - }.map { it.toDomain() } +// override suspend fun createBlob( +// userId: String, +// contentType: String, +// digest: String, +// content: ByteArray, +// sessionToken: String +// ) = runCatchingNetworkExceptions { +// val requestBody = content.toRequestBody(contentType.toMediaType()) +// blobApi.createBlob( +// sessionToken = sessionToken, +// userId = userId, +// contentType = contentType, +// digest = digest, +// content = requestBody, +// ) +// }.map { it.toDomain() } override suspend fun deleteAllBlobs( userId: String, @@ -69,16 +67,16 @@ class BlobRepositoryImpl( blobApi.deleteBlob(sessionToken = sessionToken, blobId = blobId) } - override suspend fun getBlobContent( - blobId: String, - sessionToken: String, - ) = runCatchingNetworkExceptions { - val responseBody = blobApi.getBlobContent( - sessionToken = sessionToken, - blobId = blobId, - ) - responseBody.bytes() - } +// override suspend fun getBlobContent( +// blobId: String, +// sessionToken: String, +// ) = runCatchingNetworkExceptions { +// val responseBody = blobApi.getBlobContent( +// sessionToken = sessionToken, +// blobId = blobId, +// ) +// responseBody.bytes() +// } override suspend fun uploadDeviceLogs( userId: String, diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/ClinicRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/ClinicRepositoryImpl.kt similarity index 93% rename from data/src/main/kotlin/org/tidepool/sdk/repository/ClinicRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/ClinicRepositoryImpl.kt index fad03a2..d97dbc3 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/repository/ClinicRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/ClinicRepositoryImpl.kt @@ -1,11 +1,9 @@ package org.tidepool.sdk.repository import org.tidepool.sdk.api.ClinicApi -import org.tidepool.sdk.dto.clinic.ClinicDto import org.tidepool.sdk.dto.clinic.ClinicianDto -import org.tidepool.sdk.dto.clinic.PatientDto -import org.tidepool.sdk.dto.clinic.fromDomain import org.tidepool.sdk.dto.clinic.toDomain +import org.tidepool.sdk.dto.clinic.toDto import org.tidepool.sdk.mapList import org.tidepool.sdk.model.clinic.Clinic import org.tidepool.sdk.model.clinic.Clinician @@ -43,7 +41,7 @@ class ClinicRepositoryImpl( ): Result = runCatchingNetworkExceptions { clinicApi.createClinic( sessionToken = sessionToken, - clinic = ClinicDto.fromDomain(clinic), + clinic = clinic.toDto(), ) }.map { it.toDomain() } @@ -69,7 +67,7 @@ class ClinicRepositoryImpl( clinicApi.updateClinic( sessionToken = sessionToken, clinicId = clinicId, - clinic = ClinicDto.fromDomain(clinic), + clinic = clinic.toDto(), ) }.map { it.toDomain() } @@ -109,7 +107,7 @@ class ClinicRepositoryImpl( clinicApi.addClinicianToClinic( sessionToken = sessionToken, clinicId = clinicId, - clinician = ClinicianDto.fromDomain(clinician), + clinician = clinician.toDto(), ) }.map { it.toDomain() } @@ -150,7 +148,7 @@ class ClinicRepositoryImpl( sessionToken = sessionToken, clinicId = clinicId, patientId = patientId, - patient = PatientDto.fromDomain(patient) + patient = patient.toDto() ) }.map { it.toDomain() } diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/ConfirmationRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/ConfirmationRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/ConfirmationRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/ConfirmationRepositoryImpl.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/DataRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/DataRepositoryImpl.kt similarity index 54% rename from data/src/main/kotlin/org/tidepool/sdk/repository/DataRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/DataRepositoryImpl.kt index 2790a9b..b8d42ef 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/repository/DataRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/DataRepositoryImpl.kt @@ -1,32 +1,43 @@ package org.tidepool.sdk.repository import org.tidepool.sdk.api.DataApi -import org.tidepool.sdk.database.DataDao +import org.tidepool.sdk.database.BasalAutomatedDataDao +import org.tidepool.sdk.database.BolusDataDao +import org.tidepool.sdk.database.CgmSettingsDataDao +import org.tidepool.sdk.database.ControllerSettingsDataDao +import org.tidepool.sdk.database.ContinuousGlucoseDataDao +import org.tidepool.sdk.database.DeviceEventDataDao +import org.tidepool.sdk.database.DosingDecisionDataDao +import org.tidepool.sdk.database.FoodDataDao +import org.tidepool.sdk.database.InsulinDataDao +import org.tidepool.sdk.database.PumpSettingsDataDao import org.tidepool.sdk.database.entity.data.BasalAutomatedDataEntity import org.tidepool.sdk.database.entity.data.BolusDataEntity +import org.tidepool.sdk.database.entity.data.CgmSettingsDataEntity import org.tidepool.sdk.database.entity.data.ContinuousGlucoseDataEntity +import org.tidepool.sdk.database.entity.data.ControllerSettingsDataEntity +import org.tidepool.sdk.database.entity.data.DeviceEventDataEntity import org.tidepool.sdk.database.entity.data.DosingDecisionDataEntity import org.tidepool.sdk.database.entity.data.FoodDataEntity import org.tidepool.sdk.database.entity.data.InsulinDataEntity -import org.tidepool.sdk.database.entity.data.toDto +import org.tidepool.sdk.database.entity.data.PumpSettingsDataEntity import org.tidepool.sdk.database.entity.data.toEntity import org.tidepool.sdk.dto.data.BasalAutomatedDataDto import org.tidepool.sdk.dto.data.BaseDataDto import org.tidepool.sdk.dto.data.BolusDataDto +import org.tidepool.sdk.dto.data.CgmSettingsDataDto import org.tidepool.sdk.dto.data.ContinuousGlucoseDataDto +import org.tidepool.sdk.dto.data.ControllerSettingsDataDto +import org.tidepool.sdk.dto.data.DeviceEventDataDto +import org.tidepool.sdk.dto.data.DosingDecisionDataDto +import org.tidepool.sdk.dto.data.FoodDataDto +import org.tidepool.sdk.dto.data.InsulinDataDto +import org.tidepool.sdk.dto.data.PumpSettingsDataDto import org.tidepool.sdk.dto.data.toDomain import org.tidepool.sdk.dto.data.toDto import org.tidepool.sdk.mapList import org.tidepool.sdk.model.data.BaseData import org.tidepool.sdk.model.data.DataType -import org.tidepool.sdk.dto.data.DataSetDto -import org.tidepool.sdk.dto.data.DataSourceDto -import org.tidepool.sdk.dto.data.DosingDecisionDataDto -import org.tidepool.sdk.dto.data.FoodDataDto -import org.tidepool.sdk.dto.data.InsulinDataDto -import org.tidepool.sdk.dto.data.NewDataSetDto -import org.tidepool.sdk.dto.data.NewDataSourceDto -import org.tidepool.sdk.dto.data.fromDomain import org.tidepool.sdk.model.data.DataSet import org.tidepool.sdk.model.data.DataSource import org.tidepool.sdk.model.data.NewDataSet @@ -34,12 +45,79 @@ import org.tidepool.sdk.model.data.NewDataSource import org.tidepool.sdk.runCatchingNetworkExceptions import java.time.Instant import kotlin.collections.toTypedArray +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock class DataRepositoryImpl( private val dataApi: DataApi, - private val dataDao: DataDao, + private val basalAutomatedDataDao: BasalAutomatedDataDao, + private val bolusDataDao: BolusDataDao, + private val continuousGlucoseDataDao: ContinuousGlucoseDataDao, + private val dosingDecisionDataDao: DosingDecisionDataDao, + private val foodDataDao: FoodDataDao, + private val insulinDataDao: InsulinDataDao, + private val deviceEventDataDao: DeviceEventDataDao, + private val cgmSettingsDataDao: CgmSettingsDataDao, + private val controllerSettingsDataDao: ControllerSettingsDataDao, + private val pumpSettingsDataDao: PumpSettingsDataDao, + private val keyValueStorage: KeyValueStorage, ) : DataRepository { - + + private val KEY_CACHED_DATA_SET_ID: String = "KEY_CACHED_DATA_SET_ID" + + private var cachedDataSetId: String? = null + get() = field ?: keyValueStorage.getString(KEY_CACHED_DATA_SET_ID) + .also { field = it } + set(value) { + field = value + keyValueStorage.putString(KEY_CACHED_DATA_SET_ID, value) + } + + private val dataSetIdMutex: Mutex = Mutex() + private var dataSetIdDeferred: CompletableDeferred? = null + + override suspend fun awaitOrCreateCachedDataSetId( + create: suspend () -> Result, + ): Result { + // Fast-path when already available + cachedDataSetId?.let { return Result.success(it) } + + var isCreator = false + val localDeferred: CompletableDeferred = dataSetIdMutex.withLock { + // Re-check after acquiring the lock + cachedDataSetId?.let { return Result.success(it) } + if (dataSetIdDeferred == null) { + dataSetIdDeferred = CompletableDeferred() + isCreator = true + } + dataSetIdDeferred!! + } + + if (isCreator) { + val result = create() + dataSetIdMutex.withLock { + if (result.isSuccess) { + val id = result.getOrThrow() + cachedDataSetId = id + dataSetIdDeferred?.complete(id) + } else { + val throwable = result.exceptionOrNull() + ?: IllegalStateException("Unknown error creating dataset id") + dataSetIdDeferred?.completeExceptionally(throwable) + } + dataSetIdDeferred = null + } + return result + } + + return try { + Result.success(localDeferred.await()) + } catch (t: Throwable) { + Result.failure(t) + } + } + override suspend fun getDataForUser( userId: String, uploadId: String?, @@ -57,7 +135,7 @@ class DataRepositoryImpl( ?.map { it.toDto() } ?.toTypedArray() ?.let { DataApi.CommaSeparatedArray(*it) } - + dataApi.getDataForUser( sessionToken = sessionToken, userId = userId, @@ -72,7 +150,7 @@ class DataRepositoryImpl( medtronic = medtronic ) }.mapList { it.toDomain() } - + // Data Sets operations override suspend fun getUserDataSets( userId: String, @@ -82,51 +160,51 @@ class DataRepositoryImpl( ) = runCatchingNetworkExceptions { dataApi.getUserDataSets(sessionToken, userId) }.mapList { it.toDomain() } - + override suspend fun createDataSet( userId: String, newDataSet: NewDataSet, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.createDataSet( sessionToken = sessionToken, userId = userId, - newDataSet = NewDataSetDto.fromDomain(newDataSet), + newDataSet = newDataSet.toDto(), ) }.map { it.toDomain() } - + override suspend fun getDataSet( dataSetId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.getDataSet(sessionToken, dataSetId) }.map { it.toDomain() } - + override suspend fun updateDataSet( dataSetId: String, dataSet: DataSet, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.updateDataSet( sessionToken = sessionToken, dataSetId = dataSetId, - dataSet = DataSetDto.fromDomain(dataSet), + dataSet = dataSet.toDto(), ) }.map { it.toDomain() } - + override suspend fun deleteDataSet( dataSetId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.deleteDataSet(sessionToken, dataSetId) } - + override suspend fun uploadDataToDataSet( dataSetId: String, data: List, - sessionToken: String + sessionToken: String, ): Result> { - val dtos = data.map { BaseDataDto.fromDomain(it) } + val dtos = data.map { it.toDto() } return runCatchingNetworkExceptions { dataApi.uploadDataToDataSet( sessionToken = sessionToken, @@ -134,198 +212,190 @@ class DataRepositoryImpl( data = dtos, ) } + .map { it.data } .cacheOnFailure(dtos) .mapList { it.toDomain() } } - + override suspend fun deleteDataSetData( dataSetId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.deleteDataSetData(sessionToken, dataSetId) } - + // Legacy datasets operations override suspend fun getUserDataSetsLegacy( userId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.getUserDataSetsLegacy(sessionToken, userId) }.mapList { it.toDomain() } - + override suspend fun createDataSetLegacy( userId: String, newDataSet: NewDataSet, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.createDataSetLegacy( sessionToken = sessionToken, userId = userId, - newDataSet = NewDataSetDto.fromDomain(newDataSet), + newDataSet = newDataSet.toDto(), ) }.map { it.toDomain() } - + override suspend fun getDataSetLegacy( dataSetId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.getDataSetLegacy(sessionToken, dataSetId) }.map { it.toDomain() } - + override suspend fun updateDataSetLegacy( dataSetId: String, dataSet: DataSet, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.updateDataSetLegacy( sessionToken = sessionToken, dataSetId = dataSetId, - dataSet = DataSetDto.fromDomain(dataSet), + dataSet = dataSet.toDto(), ) }.map { it.toDomain() } - + override suspend fun deleteDataSetLegacy( dataSetId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.deleteDataSetLegacy(sessionToken, dataSetId) } - + override suspend fun uploadDataToDataSetLegacy( dataSetId: String, data: List, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.uploadDataToDataSetLegacy( sessionToken = sessionToken, dataSetId = dataSetId, - data = data.map { BaseDataDto.fromDomain(it) } + data = data.map { it.toDto() } ) }.mapList { it.toDomain() } - + // Data Sources operations override suspend fun getUserDataSources( userId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.getUserDataSources(sessionToken, userId) }.mapList { it.toDomain() } - + override suspend fun createDataSource( userId: String, newDataSource: NewDataSource, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.createDataSource( sessionToken = sessionToken, userId = userId, - newDataSource = NewDataSourceDto.fromDomain(newDataSource) + newDataSource = newDataSource.toDto() ) }.map { it.toDomain() } - + override suspend fun deleteAllDataSources( userId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.deleteAllDataSources(sessionToken, userId) } - + override suspend fun getDataSource( dataSourceId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.getDataSource(sessionToken, dataSourceId) }.map { it.toDomain() } - + override suspend fun updateDataSource( dataSourceId: String, dataSource: DataSource, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.updateDataSource( sessionToken = sessionToken, dataSourceId = dataSourceId, - dataSource = DataSourceDto.fromDomain(dataSource) + dataSource = dataSource.toDto() ) }.map { it.toDomain() } - + override suspend fun deleteDataSource( dataSourceId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.deleteDataSource(sessionToken, dataSourceId) } - + // Additional data operations override suspend fun deleteAllUserData( userId: String, - sessionToken: String + sessionToken: String, ) = runCatchingNetworkExceptions { dataApi.deleteAllUserData(sessionToken, userId) } - - override suspend fun uploadData( - userId: String, - data: List, - sessionToken: String - ): Result> { - val dtos = data.map { BaseDataDto.fromDomain(it) } - return runCatchingNetworkExceptions { - dataApi.uploadData( - sessionToken = sessionToken, - userId = userId, - data = dtos - ) - } - .cacheOnFailure(dtos) - .mapList { it.toDomain() } - } - + override suspend fun uploadCachedData( sessionToken: String, userId: String, ): Result = listOf( - dataDao.getAllBasalAutomatedData(), - dataDao.getAllBolusData(), - dataDao.getAllContinuousGlucoseData(), - dataDao.getAllDosingDecisionData(), - dataDao.getAllFoodData(), - dataDao.getAllInsulinData(), + basalAutomatedDataDao.getAll(), + bolusDataDao.getAll(), + continuousGlucoseDataDao.getAll(), + dosingDecisionDataDao.getAll(), + foodDataDao.getAll(), + insulinDataDao.getAll(), ).flatten().let { entities -> runCatchingNetworkExceptions { - dataApi.uploadData( + dataApi.uploadDataForUser( sessionToken = sessionToken, userId = userId, - data = entities.map { it.toDto() }, + data = emptyList(), // entities.map { it.toDto() }, ) }.map { - entities.forEach { it -> - when (it) { - is BasalAutomatedDataEntity -> dataDao.insertBasalAutomatedData(it) - is BolusDataEntity -> dataDao.insertBolusData(it) - is ContinuousGlucoseDataEntity -> dataDao.insertContinuousGlucoseData(it) - is DosingDecisionDataEntity -> dataDao.insertDosingDecisionData(it) - is FoodDataEntity -> dataDao.insertFoodData(it) - is InsulinDataEntity -> dataDao.insertInsulinData(it) + entities.forEach { entity -> + when (entity) { + is BasalAutomatedDataEntity -> basalAutomatedDataDao.delete(entity) + is BolusDataEntity -> bolusDataDao.delete(entity) + is ContinuousGlucoseDataEntity -> continuousGlucoseDataDao.delete(entity) + is DosingDecisionDataEntity -> dosingDecisionDataDao.delete(entity) + is FoodDataEntity -> foodDataDao.delete(entity) + is InsulinDataEntity -> insulinDataDao.delete(entity) + is DeviceEventDataEntity -> deviceEventDataDao.delete(entity) + is CgmSettingsDataEntity -> cgmSettingsDataDao.delete(entity) + is ControllerSettingsDataEntity -> controllerSettingsDataDao.delete(entity) + is PumpSettingsDataEntity -> pumpSettingsDataDao.delete(entity) } } } } - + private suspend fun Result>.cacheOnFailure( - toUpload: List + toUpload: List, ) = fold( onSuccess = { Result.success(it) }, onFailure = { ex -> - // TODO toUpload.forEach { dto -> when (dto) { - is BasalAutomatedDataDto -> dataDao.insertBasalAutomatedData(dto.toEntity()) - is BolusDataDto -> dataDao.insertBolusData(dto.toEntity()) - is ContinuousGlucoseDataDto -> dataDao.insertContinuousGlucoseData(dto.toEntity()) - is DosingDecisionDataDto -> dataDao.insertDosingDecisionData(dto.toEntity()) - is FoodDataDto -> dataDao.insertFoodData(dto.toEntity()) - is InsulinDataDto -> dataDao.insertInsulinData(dto.toEntity()) + is BasalAutomatedDataDto -> basalAutomatedDataDao.insert(dto.toEntity()) + is BolusDataDto -> bolusDataDao.insert(dto.toEntity()) + is ContinuousGlucoseDataDto -> continuousGlucoseDataDao.insert(dto.toEntity()) + is DosingDecisionDataDto -> dosingDecisionDataDao.insert(dto.toEntity()) + is FoodDataDto -> foodDataDao.insert(dto.toEntity()) + is InsulinDataDto -> insulinDataDao.insert(dto.toEntity()) + is DeviceEventDataDto -> deviceEventDataDao.insert(dto.toEntity()) + is CgmSettingsDataDto -> cgmSettingsDataDao.insert(dto.toEntity()) + is ControllerSettingsDataDto -> controllerSettingsDataDao.insert(dto.toEntity()) + is PumpSettingsDataDto -> pumpSettingsDataDao.insert(dto.toEntity()) + else -> println("DataRepository: Unknown data type: ${dto::class.simpleName}") } } Result.failure(ex) diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/repository/ExportRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/ExportRepositoryImpl.kt new file mode 100644 index 0000000..9dd6165 --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/ExportRepositoryImpl.kt @@ -0,0 +1,45 @@ +package org.tidepool.sdk.repository + +import org.tidepool.sdk.api.ExportApi +import org.tidepool.sdk.dto.BloodGlucoseDto +import org.tidepool.sdk.model.BloodGlucose +import org.tidepool.sdk.model.export.ExportData +import org.tidepool.sdk.model.export.ExportFormat +import org.tidepool.sdk.runCatchingNetworkExceptions +import java.time.Instant +import kotlin.toString + +class ExportRepositoryImpl( + private val exportApi: ExportApi, +) : ExportRepository { + +// override suspend fun exportUserData( +// sessionToken: String, +// userId: String, +// startDate: Instant?, +// endDate: Instant?, +// bgUnits: BloodGlucose.Units, +// format: ExportFormat, +// ): Result = runCatchingNetworkExceptions { +// exportApi.exportUserData( +// sessionToken = sessionToken, +// userId = userId, +// startDate = startDate, +// endDate = endDate, +// format = format.fileType, +// bgUnits = bgUnits.shorthand, +// ) +// }.map { it.toExportData(format) } +} + +//internal fun ResponseBody.toExportData(format: ExportFormat): ExportData { +// val contentType = this.contentType()?.toString() ?: format.contentType +// val fileName = "TidepoolExport." + format.fileType +// +// return ExportData( +// data = this.byteStream(), +// format = format, +// contentType = contentType, +// fileName = fileName +// ) +//} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/GeneralRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/GeneralRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/GeneralRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/GeneralRepositoryImpl.kt diff --git a/data/src/commonMain/kotlin/org/tidepool/sdk/repository/KeyValueStorage.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/KeyValueStorage.kt new file mode 100644 index 0000000..21a356c --- /dev/null +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/KeyValueStorage.kt @@ -0,0 +1,18 @@ +package org.tidepool.sdk.repository + +interface KeyValueStorage { + fun getString(key: String): String? + fun putString(key: String, value: String?) + + fun getInt(key: String): Int? + fun putInt(key: String, value: Int?) + + fun getLong(key: String): Long? + fun putLong(key: String, value: Long?) + + fun getFloat(key: String): Float? + fun putFloat(key: String, value: Float?) + + fun getBoolean(key: String): Boolean? + fun putBoolean(key: String, value: Boolean?) +} diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/MessageRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/MessageRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/MessageRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/MessageRepositoryImpl.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/MetadataRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/MetadataRepositoryImpl.kt similarity index 95% rename from data/src/main/kotlin/org/tidepool/sdk/repository/MetadataRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/MetadataRepositoryImpl.kt index a06eb36..4e1284c 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/repository/MetadataRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/MetadataRepositoryImpl.kt @@ -5,9 +5,8 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.encodeToJsonElement import org.tidepool.sdk.api.MetadataApi import org.tidepool.sdk.api.UserApi -import org.tidepool.sdk.dto.metadata.UserProfileDto -import org.tidepool.sdk.dto.metadata.fromDomain import org.tidepool.sdk.dto.metadata.toDomain +import org.tidepool.sdk.dto.metadata.toDto import org.tidepool.sdk.dto.metadata.users.toDomain import org.tidepool.sdk.mapList import org.tidepool.sdk.model.metadata.UserProfile @@ -45,7 +44,7 @@ class MetadataRepositoryImpl( usePost: Boolean ): Result = runCatchingNetworkExceptions { val json = Json.encodeToJsonElement( - UserProfileDto.fromDomain(collection), + collection.toDto(), ) as JsonObject if (usePost) { diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/MetricsRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/MetricsRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/MetricsRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/MetricsRepositoryImpl.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/PrescriptionRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/PrescriptionRepositoryImpl.kt similarity index 92% rename from data/src/main/kotlin/org/tidepool/sdk/repository/PrescriptionRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/PrescriptionRepositoryImpl.kt index dae09fd..a2c08a1 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/repository/PrescriptionRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/PrescriptionRepositoryImpl.kt @@ -2,9 +2,8 @@ package org.tidepool.sdk.repository import org.tidepool.sdk.api.PrescriptionApi import org.tidepool.sdk.dto.prescription.NewPrescriptionDto -import org.tidepool.sdk.dto.prescription.UpdatePrescriptionDto -import org.tidepool.sdk.dto.prescription.fromDomain import org.tidepool.sdk.dto.prescription.toDomain +import org.tidepool.sdk.dto.prescription.toDto import org.tidepool.sdk.mapList import org.tidepool.sdk.model.prescription.NewPrescription import org.tidepool.sdk.model.prescription.Prescription @@ -21,7 +20,7 @@ class PrescriptionRepositoryImpl( ): Result = runCatchingNetworkExceptions { prescriptionApi.createPrescription( sessionToken = sessionToken, - requestBody = NewPrescriptionDto.fromDomain(newPrescription), + requestBody = newPrescription.toDto(), ) }.map { it.toDomain() } @@ -43,7 +42,7 @@ class PrescriptionRepositoryImpl( prescriptionApi.updatePrescription( sessionToken = sessionToken, prescriptionId = prescriptionId, - requestBody = UpdatePrescriptionDto.fromDomain(updatePrescription), + requestBody = updatePrescription.toDto(), ) }.map { it.toDomain() } diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/SummaryRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/SummaryRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/SummaryRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/SummaryRepositoryImpl.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/TaskRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/TaskRepositoryImpl.kt similarity index 100% rename from data/src/main/kotlin/org/tidepool/sdk/repository/TaskRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/TaskRepositoryImpl.kt diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/UserRepositoryImpl.kt b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/UserRepositoryImpl.kt similarity index 95% rename from data/src/main/kotlin/org/tidepool/sdk/repository/UserRepositoryImpl.kt rename to data/src/commonMain/kotlin/org/tidepool/sdk/repository/UserRepositoryImpl.kt index ac4d579..44e96e9 100644 --- a/data/src/main/kotlin/org/tidepool/sdk/repository/UserRepositoryImpl.kt +++ b/data/src/commonMain/kotlin/org/tidepool/sdk/repository/UserRepositoryImpl.kt @@ -1,7 +1,6 @@ package org.tidepool.sdk.repository import org.tidepool.sdk.api.UserApi -import org.tidepool.sdk.dto.user.UserDto import org.tidepool.sdk.dto.user.toDomain import org.tidepool.sdk.model.metadata.users.User import org.tidepool.sdk.runCatchingNetworkExceptions diff --git a/data/src/main/kotlin/org/tidepool/sdk/NetworkExceptions.kt b/data/src/main/kotlin/org/tidepool/sdk/NetworkExceptions.kt deleted file mode 100644 index 7a7f16d..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/NetworkExceptions.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.tidepool.sdk - -import retrofit2.HttpException - -/** - * Helper function to map HttpException to specific Tidepool network exceptions - */ -fun HttpException.toTidepoolException() = when (code()) { - 400 -> BadRequestException("Bad request: ${message()}", this) - 401 -> UnauthorizedException("Unauthorized: ${message()}", this) - 403 -> ForbiddenException("Forbidden: ${message()}", this) - 404 -> NotFoundException("Not found: ${message()}", this) - 409 -> ConflictException("Conflict: ${message()}", this) - 422 -> ValidationException("Validation error: ${message()}", this) - 429 -> TooManyRequestsException("Too many requests: ${message()}", this) - 500 -> InternalServerErrorException("Internal server error: ${message()}", this) - 502 -> BadGatewayException("Bad gateway: ${message()}", this) - 503 -> ServiceUnavailableException("Service unavailable: ${message()}", this) - 504 -> GatewayTimeoutException("Gateway timeout: ${message()}", this) - else -> UnknownNetworkException("HTTP ${code()}: ${message()}", this) -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/api/ExportApi.kt b/data/src/main/kotlin/org/tidepool/sdk/api/ExportApi.kt deleted file mode 100644 index 71d373c..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/api/ExportApi.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.tidepool.sdk.api - -import okhttp3.ResponseBody -import retrofit2.http.GET -import retrofit2.http.Header -import retrofit2.http.Path -import retrofit2.http.Query -import java.time.Instant - -interface ExportApi { - - @GET("/export/{userId}") - suspend fun exportUserData( - @Header("X-Tidepool-Session-Token") sessionToken: String, - @Path("userId") userId: String, - @Query("startDate") startDate: Instant? = null, - @Query("endDate") endDate: Instant? = null, - @Query("format") format: String = "xlsx", - @Query("bgUnits") bgUnits: String = "mmol/L" - ): ResponseBody -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/DataDao.kt b/data/src/main/kotlin/org/tidepool/sdk/database/DataDao.kt deleted file mode 100644 index f954568..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/database/DataDao.kt +++ /dev/null @@ -1,114 +0,0 @@ -package org.tidepool.sdk.database - -import androidx.room.Dao -import androidx.room.Delete -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import androidx.room.Update -import org.tidepool.sdk.database.entity.data.BasalAutomatedDataEntity -import org.tidepool.sdk.database.entity.data.BolusDataEntity -import org.tidepool.sdk.database.entity.data.ContinuousGlucoseDataEntity -import org.tidepool.sdk.database.entity.data.DosingDecisionDataEntity -import org.tidepool.sdk.database.entity.data.FoodDataEntity -import org.tidepool.sdk.database.entity.data.InsulinDataEntity - -@Dao -interface DataDao { - - // BasalAutomatedDataEntity operations - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertBasalAutomatedData(data: BasalAutomatedDataEntity) - - @Update - suspend fun updateBasalAutomatedData(data: BasalAutomatedDataEntity) - - @Delete - suspend fun deleteBasalAutomatedData(data: BasalAutomatedDataEntity) - - @Query("SELECT * FROM basal_automated_data WHERE id = :id") - suspend fun getBasalAutomatedDataById(id: String): BasalAutomatedDataEntity? - - @Query("SELECT * FROM basal_automated_data") - suspend fun getAllBasalAutomatedData(): List - - // BolusDataEntity operations - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertBolusData(data: BolusDataEntity) - - @Update - suspend fun updateBolusData(data: BolusDataEntity) - - @Delete - suspend fun deleteBolusData(data: BolusDataEntity) - - @Query("SELECT * FROM bolus_data WHERE id = :id") - suspend fun getBolusDataById(id: String): BolusDataEntity? - - @Query("SELECT * FROM bolus_data") - suspend fun getAllBolusData(): List - - // ContinuousGlucoseDataEntity operations - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertContinuousGlucoseData(data: ContinuousGlucoseDataEntity) - - @Update - suspend fun updateContinuousGlucoseData(data: ContinuousGlucoseDataEntity) - - @Delete - suspend fun deleteContinuousGlucoseData(data: ContinuousGlucoseDataEntity) - - @Query("SELECT * FROM continuous_glucose_data WHERE id = :id") - suspend fun getContinuousGlucoseDataById(id: String): ContinuousGlucoseDataEntity? - - @Query("SELECT * FROM continuous_glucose_data") - suspend fun getAllContinuousGlucoseData(): List - - // DosingDecisionDataEntity operations - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertDosingDecisionData(data: DosingDecisionDataEntity) - - @Update - suspend fun updateDosingDecisionData(data: DosingDecisionDataEntity) - - @Delete - suspend fun deleteDosingDecisionData(data: DosingDecisionDataEntity) - - @Query("SELECT * FROM dosing_decision_data WHERE id = :id") - suspend fun getDosingDecisionDataById(id: String): DosingDecisionDataEntity? - - @Query("SELECT * FROM dosing_decision_data") - suspend fun getAllDosingDecisionData(): List - - // FoodDataEntity operations - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertFoodData(data: FoodDataEntity) - - @Update - suspend fun updateFoodData(data: FoodDataEntity) - - @Delete - suspend fun deleteFoodData(data: FoodDataEntity) - - @Query("SELECT * FROM food_data WHERE id = :id") - suspend fun getFoodDataById(id: String): FoodDataEntity? - - @Query("SELECT * FROM food_data") - suspend fun getAllFoodData(): List - - // InsulinDataEntity operations - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun insertInsulinData(data: InsulinDataEntity) - - @Update - suspend fun updateInsulinData(data: InsulinDataEntity) - - @Delete - suspend fun deleteInsulinData(data: InsulinDataEntity) - - @Query("SELECT * FROM insulin_data WHERE id = :id") - suspend fun getInsulinDataById(id: String): InsulinDataEntity? - - @Query("SELECT * FROM insulin_data") - suspend fun getAllInsulinData(): List -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/database/LoopKitDatabase.kt b/data/src/main/kotlin/org/tidepool/sdk/database/LoopKitDatabase.kt deleted file mode 100644 index 4454066..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/database/LoopKitDatabase.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.tidepool.sdk.database - -import androidx.room.Database -import androidx.room.RoomDatabase -import androidx.room.TypeConverters -import org.tidepool.sdk.database.entity.data.BasalAutomatedDataEntity -import org.tidepool.sdk.database.entity.data.BaseDataEntity -import org.tidepool.sdk.database.entity.data.BolusDataEntity -import org.tidepool.sdk.database.entity.data.ContinuousGlucoseDataEntity -import org.tidepool.sdk.database.entity.data.DosingDecisionDataEntity -import org.tidepool.sdk.database.entity.data.FoodDataEntity -import org.tidepool.sdk.database.entity.data.InsulinDataEntity - -@Database( - version = 1, - exportSchema = false, - entities = [ - BaseDataEntity::class, - BasalAutomatedDataEntity::class, - BolusDataEntity::class, - ContinuousGlucoseDataEntity::class, - DosingDecisionDataEntity::class, - FoodDataEntity::class, - InsulinDataEntity::class, - ], -) -@TypeConverters(DatabaseConverters::class) -abstract class LoopKitDatabase : RoomDatabase() { - - abstract fun dataDao(): DataDao -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/AssociationDto.kt b/data/src/main/kotlin/org/tidepool/sdk/dto/AssociationDto.kt deleted file mode 100644 index b68779e..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/AssociationDto.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.tidepool.sdk.dto - -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.Association - -@Serializable -@KonvertTo(Association::class, mapFunctionName = "toDomain") -data class AssociationDto( - @SerialName("type") - val type: AssociationTypeDto?, - - val id: String?, - @SerialName("url") - val url: String?, - @SerialName("reason") - val reason: String?, -) { - - @KonvertFrom(Association::class, mapFunctionName = "fromDomain") - companion object {} - - @Serializable - enum class AssociationTypeDto { - - @SerialName("blob") - Blob, - - @SerialName("datum") - Datum, - - @SerialName("image") - Image, - - @SerialName("url") - Url, - ; - } -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/ClinicDto.kt b/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/ClinicDto.kt deleted file mode 100644 index e443dfc..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/ClinicDto.kt +++ /dev/null @@ -1,102 +0,0 @@ -package org.tidepool.sdk.dto.clinic - -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo -import kotlinx.serialization.Contextual -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.tidepool.sdk.dto.BloodGlucoseDto -import org.tidepool.sdk.model.clinic.Clinic -import java.time.Instant - -@Serializable -@KonvertTo(Clinic::class, mapFunctionName = "toDomain") -data class ClinicDto( - @SerialName("id") - val id: String, - @SerialName("name") - val name: String, - @SerialName("shareCode") - val shareCode: String, - @SerialName("address") - val address: String? = null, - @SerialName("city") - val city: String? = null, - @SerialName("postalCode") - val postalCode: String? = null, - @SerialName("state") - val state: String? = null, - @SerialName("country") - val country: String? = null, - @SerialName("patientTags") - val patientTags: List? = null, - @SerialName("sites") - val sites: List? = null, - @SerialName("lastDeletedPatientTag") - val lastDeletedPatientTag: PatientTagDto? = null, - @SerialName("phoneNumbers") - val phoneNumbers: PhoneNumbersDto? = null, - @SerialName("clinicType") - val clinicType: ClinicType? = null, - @SerialName("clinicSize") - val clinicSize: ClinicSize? = null, - @SerialName("canMigrate") - val canMigrate: Boolean, - @SerialName("website") - val website: String? = null, - @Contextual - @SerialName("createdTime") - val createdTime: Instant, - @Contextual - @SerialName("updatedTime") - val updatedTime: Instant, - @SerialName("tierDescription") - val tierDescription: String, - @SerialName("tier") - val tier: String, - @SerialName("preferredBgUnits") - val preferredBgUnits: BloodGlucoseDto.UnitsDto, - @SerialName("suppressedNotifications") - val suppressedNotifications: SuppressedNotificationsDto? = null, - @SerialName("timezone") - val timezone: String? = null, -) { - @KonvertFrom(Clinic::class, mapFunctionName = "fromDomain") - companion object -} - -@Serializable -enum class ClinicType { - - @SerialName("provider_practice") - ProviderPractice, - - @SerialName("healthcare_system") - HealthcareSystem, - - @SerialName("veterinary_clinic") - VeterinaryClinic, - - @SerialName("researcher") - Researcher, - - @SerialName("other") - Other, -} - -@Serializable -enum class ClinicSize { - - @SerialName("0-249") - Small, - - @SerialName("250-499") - Medium, - - @SerialName("500-999") - Large, - - @SerialName("1000+") - Huge, - ; -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/ClinicianDto.kt b/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/ClinicianDto.kt deleted file mode 100644 index 8bf976c..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/clinic/ClinicianDto.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.tidepool.sdk.dto.clinic - -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo -import kotlinx.serialization.Contextual -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.clinic.Clinician -import java.time.Instant - -@Serializable -@KonvertTo(Clinician::class, mapFunctionName = "toDomain") -data class ClinicianDto( - @SerialName("id") - val id: String? = null, - @SerialName("inviteId") - val inviteId: String? = null, - @SerialName("email") - val email: String, - @SerialName("name") - val name: String, - @SerialName("roles") - val roles: List, - @Contextual - @SerialName("createdTime") - val createdTime: Instant? = null, - @Contextual - @SerialName("updatedTime") - val updatedTime: Instant? = null -) { - - @KonvertFrom(Clinician::class, mapFunctionName = "fromDomain") - companion object {} -} - -@Serializable -enum class ClinicianRole { - @SerialName("CLINIC_ADMIN") - ClinicAdmin, - @SerialName("CLINIC_MEMBER") - ClinicMember, - @SerialName("PRESCRIBER") - Prescriber, - ; -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/BasalAutomatedDataDto.kt b/data/src/main/kotlin/org/tidepool/sdk/dto/data/BasalAutomatedDataDto.kt deleted file mode 100644 index e64b4f9..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/BasalAutomatedDataDto.kt +++ /dev/null @@ -1,72 +0,0 @@ -package org.tidepool.sdk.dto.data - -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo -import kotlinx.serialization.Contextual -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.data.BasalAutomatedData -import org.tidepool.sdk.dto.AssociationDto -import java.time.Instant -import java.util.TimeZone -import kotlin.time.Duration - -// TODO: Finish implementing automated.v1 -@Serializable -@KonvertTo(BasalAutomatedData::class, mapFunctionName = "toDomain") -data class BasalAutomatedDataDto( - override val id: String = "", - override val type: DataTypeDto = DataTypeDto.Alert, - @Contextual - override val time: Instant? = null, - override val annotations: List> = emptyList(), - override val associations: List = emptyList(), - @Contextual - override val clockDriftOffset: Duration? = null, - @Contextual - override val conversionOffset: Duration? = null, - override val dataSetId: String? = null, - override val deviceTime: String? = null, - override val notes: List = emptyList(), - @Contextual - override val timeZone: TimeZone? = null, - @Contextual - override val timeZoneOffset: Duration? = null, - - @SerialName("deliveryType") - val deliveryType: DeliveryTypeDto, - @SerialName("duration") - val duration: Int, - @SerialName("expectedDuration") - val expectedDuration: Int? = null, - @SerialName("rate") - val rate: Double = -1.0, - @SerialName("scheduleName") - val scheduleName: String? = null, -) : BaseDataDto() { - - - @KonvertFrom(BasalAutomatedData::class, mapFunctionName = "fromDomain") - companion object {} - - val insulinFormulation: Nothing - get() = TODO("schema \"formulation.v1\" not implemented") - val suppressed: Nothing - get() = TODO("schema \"scheduled.v1\" not implemented") - - @Serializable - enum class DeliveryTypeDto { - - @SerialName("automated") - Automated, - - @SerialName("scheduled") - Scheduled, - - @SerialName("suspend") - Suspend, - - @SerialName("temp") - Temp, - } -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/BolusDataDto.kt b/data/src/main/kotlin/org/tidepool/sdk/dto/data/BolusDataDto.kt deleted file mode 100644 index 9527e7c..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/BolusDataDto.kt +++ /dev/null @@ -1,78 +0,0 @@ -package org.tidepool.sdk.dto.data - -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo -import kotlinx.serialization.Contextual -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.tidepool.sdk.dto.AssociationDto -import org.tidepool.sdk.model.data.BolusData -import java.time.Instant -import java.util.TimeZone -import kotlin.time.Duration - -// schema bolus.v1 -// line 2330 -@Serializable -@KonvertTo(BolusData::class, mapFunctionName = "toDomain") -data class BolusDataDto( - override val id: String = "", - override val type: DataTypeDto = DataTypeDto.Alert, - @Contextual - override val time: Instant? = null, - override val annotations: List> = emptyList(), - override val associations: List = emptyList(), - @Contextual - override val clockDriftOffset: Duration? = null, - @Contextual - override val conversionOffset: Duration? = null, - override val dataSetId: String? = null, - override val deviceTime: String? = null, - override val notes: List = emptyList(), - @Contextual - override val timeZone: TimeZone? = null, - @Contextual - override val timeZoneOffset: Duration? = null, - - @SerialName("subType") - val subType: BolusSubtypeDto = BolusSubtypeDto.Normal, - @SerialName("deliveryContext") - val deliveryContext: DeliveryContextDto, -) : BaseDataDto() { - - @KonvertFrom(BolusData::class, mapFunctionName = "fromDomain") - companion object {} - - val insulinFormulation: Nothing - get() = TODO("schema \"formulation.v1\" not implemented") -} - -@Serializable -enum class BolusSubtypeDto { - @SerialName("automated") - Automated, - @SerialName("dual/square") - DualSquare, - @SerialName("normal") - Normal, - @SerialName("square") - Square, - ; -} - -@Serializable -enum class DeliveryContextDto { - - @SerialName("device") - Device, - - @SerialName("algorithm") - Algorithm, - - @SerialName("remote") - Remote, - - @SerialName("undetermined") - Undetermined, - ; -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/dto/data/DataSetDto.kt b/data/src/main/kotlin/org/tidepool/sdk/dto/data/DataSetDto.kt deleted file mode 100644 index 7a80ff6..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/dto/data/DataSetDto.kt +++ /dev/null @@ -1,101 +0,0 @@ -package org.tidepool.sdk.dto.data - -import io.mcarle.konvert.api.KonvertFrom -import io.mcarle.konvert.api.KonvertTo -import kotlinx.serialization.Contextual -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.tidepool.sdk.model.data.DosingDecisionData -import java.time.Instant -import kotlin.time.Duration -import org.tidepool.sdk.model.data.DataSet -import org.tidepool.sdk.model.data.ClientSoftware -import org.tidepool.sdk.model.data.DeduplicatorDescriptor - -@Serializable -@KonvertTo(DataSet::class, mapFunctionName = "toDomain") -data class DataSetDto( - @SerialName("annotations") - val annotations: List>? = null, - @SerialName("byUser") - val byUser: String? = null, - @SerialName("client") - val client: ClientSoftwareDto? = null, - @SerialName("clockDriftOffset") - @Contextual val clockDriftOffset: Duration? = null, - @SerialName("computerTime") - val computerTime: String? = null, - @SerialName("conversionOffset") - @Contextual val conversionOffset: Duration? = null, - @SerialName("createdTime") - @Contextual val createdTime: Instant? = null, - @SerialName("createdUserId") - val createdUserId: String? = null, - @SerialName("dataSetType") - val dataSetType: String? = null, - @SerialName("deduplicator") - val deduplicator: DeduplicatorDescriptorDto? = null, - @SerialName("deletedTime") - @Contextual val deletedTime: Instant? = null, - @SerialName("deletedUserId") - val deletedUserId: String? = null, - @SerialName("deviceId") - val deviceId: String? = null, - @SerialName("deviceManufacturers") - val deviceManufacturers: List? = null, - @SerialName("deviceModel") - val deviceModel: String? = null, - @SerialName("deviceSerialNumber") - val deviceSerialNumber: String? = null, - @SerialName("deviceTags") - val deviceTags: List? = null, - @SerialName("id") - val id: String? = null, - @SerialName("modifiedTime") - @Contextual val modifiedTime: Instant? = null, - @SerialName("modifiedUserId") - val modifiedUserId: String? = null, - @SerialName("state") - val state: String? = null, - @SerialName("time") - @Contextual val time: Instant? = null, - @SerialName("timeProcessing") - val timeProcessing: String? = null, - @SerialName("timezone") - val timezone: String? = null, - @SerialName("timezoneOffset") - @Contextual val timezoneOffset: Duration? = null, - @SerialName("type") - val type: String? = null, - @SerialName("uploadId") - val uploadId: String? = null, - @SerialName("version") - val version: String? = null -) { - @KonvertFrom(DataSet::class, mapFunctionName = "fromDomain") - companion object {} -} - -@Serializable -@KonvertTo(ClientSoftware::class, mapFunctionName = "toDomain") -data class ClientSoftwareDto( - @SerialName("name") - val name: String? = null, - @SerialName("version") - val version: String? = null -) { - @KonvertFrom(ClientSoftware::class, mapFunctionName = "fromDomain") - companion object {} -} - -@Serializable -@KonvertTo(DeduplicatorDescriptor::class, mapFunctionName = "toDomain") -data class DeduplicatorDescriptorDto( - @SerialName("name") - val name: String? = null, - @SerialName("version") - val version: String? = null -) { - @KonvertFrom(DeduplicatorDescriptor::class, mapFunctionName = "fromDomain") - companion object {} -} \ No newline at end of file diff --git a/data/src/main/kotlin/org/tidepool/sdk/repository/ExportRepositoryImpl.kt b/data/src/main/kotlin/org/tidepool/sdk/repository/ExportRepositoryImpl.kt deleted file mode 100644 index 0c3a4cc..0000000 --- a/data/src/main/kotlin/org/tidepool/sdk/repository/ExportRepositoryImpl.kt +++ /dev/null @@ -1,46 +0,0 @@ -package org.tidepool.sdk.repository - -import okhttp3.ResponseBody -import org.tidepool.sdk.api.ExportApi -import org.tidepool.sdk.dto.BloodGlucoseDto -import org.tidepool.sdk.model.BloodGlucose -import org.tidepool.sdk.model.export.ExportData -import org.tidepool.sdk.model.export.ExportFormat -import org.tidepool.sdk.runCatchingNetworkExceptions -import java.time.Instant -import kotlin.toString - -class ExportRepositoryImpl( - private val exportApi: ExportApi, -) : ExportRepository { - - override suspend fun exportUserData( - sessionToken: String, - userId: String, - startDate: Instant?, - endDate: Instant?, - bgUnits: BloodGlucose.Units, - format: ExportFormat, - ): Result = runCatchingNetworkExceptions { - exportApi.exportUserData( - sessionToken = sessionToken, - userId = userId, - startDate = startDate, - endDate = endDate, - format = format.fileType, - bgUnits = bgUnits.shorthand, - ) - }.map { it.toExportData(format) } -} - -internal fun ResponseBody.toExportData(format: ExportFormat): ExportData { - val contentType = this.contentType()?.toString() ?: format.contentType - val fileName = "TidepoolExport." + format.fileType - - return ExportData( - data = this.byteStream(), - format = format, - contentType = contentType, - fileName = fileName - ) -} \ No newline at end of file diff --git a/data/src/test/kotlin/org/tidepool/sdk/dto/alert/AlertsConfigDtoSerializationTest.kt b/data/src/test/kotlin/org/tidepool/sdk/dto/alert/AlertsConfigDtoSerializationTest.kt deleted file mode 100644 index c3ea4f1..0000000 --- a/data/src/test/kotlin/org/tidepool/sdk/dto/alert/AlertsConfigDtoSerializationTest.kt +++ /dev/null @@ -1,118 +0,0 @@ -package org.tidepool.sdk.dto.alert - -import kotlinx.serialization.json.Json -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import kotlin.test.assertContains - -class AlertConfigDtoSerializationTest { - - private val json = Json { - ignoreUnknownKeys = true - encodeDefaults = true - prettyPrint = true - } - - @Test - fun `should serialize complete AlertConfig with mixed glucose units`() { - val alertConfig = AlertConfigDto( - uploadId = "upload123", - userId = "user456", - followedUserId = "followed789", - urgentLow = UrgentGlucoseAlertDto( - enabled = true, - threshold = GlucoseDto.MgDLGlucoseDto(value = 55) - ), - low = GlucoseAlertDto( - enabled = true, - threshold = GlucoseDto.MgDLGlucoseDto(value = 70), - delayMinutes = 15, - repeatMinutes = 30 - ), - high = GlucoseAlertDto( - enabled = true, - threshold = GlucoseDto.MmolGlucoseDto(value = 10.0f), - delayMinutes = 30, - repeatMinutes = 60 - ), - noCommunication = ConnectionAlertDto( - enabled = true, - delayMinutes = 20 - ), - notLooping = ConnectionAlertDto( - enabled = false, - delayMinutes = 45 - ) - ) - - val jsonString = json.encodeToString(AlertConfigDto.serializer(), alertConfig) - val deserializedConfig = json.decodeFromString(AlertConfigDto.serializer(), jsonString) - - assertEquals(alertConfig, deserializedConfig) - - // Verify specific glucose thresholds are correctly serialized - assertContains(jsonString, "\"value\": 55") - assertContains(jsonString, "\"units\": \"mg/dL\"") - assertContains(jsonString, "\"value\": 10.0") - assertContains(jsonString, "\"units\": \"mmol/L\"") - } - - @Test - fun `should deserialize AlertConfig from JSON with mixed glucose units`() { - val jsonString = """ - { - "uploadId": "upload123", - "userId": "user456", - "followedUserId": "followed789", - "urgentLow": { - "enabled": true, - "threshold": { - "units": "mg/dL", - "value": 55 - } - }, - "low": { - "enabled": true, - "threshold": { - "units": "mg/dL", - "value": 70 - }, - "delay": 15, - "repeat": 30 - }, - "high": { - "enabled": true, - "threshold": { - "units": "mmol/L", - "value": 10.0 - }, - "delay": 30, - "repeat": 60 - }, - "noCommunication": { - "enabled": true, - "delay": 20 - }, - "notLooping": { - "enabled": false, - "delay": 45 - } - } - """.trimIndent() - - val alertConfig = json.decodeFromString(AlertConfigDto.serializer(), jsonString) - - assertEquals("upload123", alertConfig.uploadId) - assertEquals("user456", alertConfig.userId) - assertEquals("followed789", alertConfig.followedUserId) - - // Verify glucose thresholds are correctly deserialized - val urgentLowThreshold = alertConfig.urgentLow?.threshold - assert(urgentLowThreshold is GlucoseDto.MgDLGlucoseDto) - assertEquals(55, (urgentLowThreshold as GlucoseDto.MgDLGlucoseDto).value) - - val highThreshold = alertConfig.high?.threshold - assert(highThreshold is GlucoseDto.MmolGlucoseDto) - assertEquals(10.0f, (highThreshold as GlucoseDto.MmolGlucoseDto).value) - } -} \ No newline at end of file diff --git a/data/src/test/kotlin/org/tidepool/sdk/dto/alert/GlucoseDtoSerializerTest.kt b/data/src/test/kotlin/org/tidepool/sdk/dto/alert/GlucoseDtoSerializerTest.kt deleted file mode 100644 index 333978e..0000000 --- a/data/src/test/kotlin/org/tidepool/sdk/dto/alert/GlucoseDtoSerializerTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.tidepool.sdk.dto.alert - -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class GlucoseDtoSerializerTest { - - private val json = Json { - ignoreUnknownKeys = true - encodeDefaults = true - } - - @Test - fun `should serialize and deserialize MgDL glucose`() { - val glucose = GlucoseDto.MgDLGlucoseDto(value = 120) - - val jsonString = json.encodeToString(glucose) - val deserializedGlucose = json.decodeFromString(jsonString) - - assertEquals(glucose, deserializedGlucose) - assert(jsonString.contains("\"units\":\"mg/dL\"")) - assert(jsonString.contains("\"value\":120")) - } - - @Test - fun `should serialize and deserialize Mmol glucose`() { - val glucose = GlucoseDto.MmolGlucoseDto(value = 6.7f) - - val jsonString = json.encodeToString(glucose) - val deserializedGlucose = json.decodeFromString(jsonString) - - assertEquals(glucose, deserializedGlucose) - assert(jsonString.contains("\"units\":\"mmol/L\"")) - assert(jsonString.contains("\"value\":6.7")) - } - - @Test - fun `should deserialize from JSON with mgdL units`() { - val jsonString = """{"units":"mg/dL","value":85}""" - - val glucose = json.decodeFromString(jsonString) - - assertEquals(GlucoseDto.MgDLGlucoseDto(value = 85), glucose) - } - - @Test - fun `should deserialize from JSON with mmolL units`() { - val jsonString = """{"units":"mmol/L","value":4.7}""" - - val glucose = json.decodeFromString(jsonString) - - assertEquals(GlucoseDto.MmolGlucoseDto(value = 4.7f), glucose) - } - - @Test - fun `should handle case insensitive units`() { - val mgdlJson = """{"units":"MG/DL","value":100}""" - val mmolJson = """{"units":"MMOL/L","value":5.5}""" - - val mgdlGlucose = json.decodeFromString(mgdlJson) - val mmolGlucose = json.decodeFromString(mmolJson) - - assert(mgdlGlucose is GlucoseDto.MgDLGlucoseDto) - assert(mmolGlucose is GlucoseDto.MmolGlucoseDto) - } -} \ No newline at end of file diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 2a9ec37..432b7f4 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -1,15 +1,54 @@ plugins { - kotlin("jvm") + kotlin("multiplatform") kotlin("plugin.serialization") id("com.google.devtools.ksp") - // Apply the java-library plugin for API and implementation separation. - `java-library` + id("com.android.library") } kotlin { + androidTarget { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + } + } + compilerOptions { freeCompilerArgs.add("-Xcontext-parameters") } + + sourceSets { + val commonMain by getting { + dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") + implementation("io.insert-koin:koin-core:4.1.0") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.0") + implementation("com.benasher44:uuid:0.8.4") + } + } + + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + + val androidMain by getting + val androidUnitTest by getting + } +} + +android { + namespace = "org.tidepool.domain" + compileSdk = 34 + + defaultConfig { + minSdk = 26 + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } } repositories { @@ -17,11 +56,6 @@ repositories { google() } -dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") - implementation("io.insert-koin:koin-core:4.1.0") -} - // Apply a specific Java toolchain to ease working on different environments. java { toolchain { diff --git a/domain/src/main/java/org/tidepool/sdk/AppLifecycleProvider.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/AppLifecycleProvider.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/AppLifecycleProvider.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/AppLifecycleProvider.kt diff --git a/domain/src/main/java/org/tidepool/sdk/AuthenticationServer.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/AuthenticationServer.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/AuthenticationServer.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/AuthenticationServer.kt diff --git a/domain/src/main/java/org/tidepool/sdk/Environment.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/Environment.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/Environment.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/Environment.kt diff --git a/domain/src/main/java/org/tidepool/sdk/NetworkExceptions.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/NetworkExceptions.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/NetworkExceptions.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/NetworkExceptions.kt diff --git a/domain/src/main/java/org/tidepool/sdk/Paginator.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/Paginator.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/Paginator.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/Paginator.kt diff --git a/domain/src/main/java/org/tidepool/sdk/PaginatorImpl.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/PaginatorImpl.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/PaginatorImpl.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/PaginatorImpl.kt diff --git a/domain/src/main/java/org/tidepool/sdk/ResultExt.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/ResultExt.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/ResultExt.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/ResultExt.kt diff --git a/domain/src/main/java/org/tidepool/sdk/TokenProvider.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/TokenProvider.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/TokenProvider.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/TokenProvider.kt diff --git a/domain/src/main/java/org/tidepool/sdk/di/DomainModule.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/di/DomainModule.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/di/DomainModule.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/di/DomainModule.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/Association.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/Association.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/Association.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/Association.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/BloodGlucose.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/BloodGlucose.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/BloodGlucose.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/BloodGlucose.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/alert/AlertConfig.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/alert/AlertConfig.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/alert/AlertConfig.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/alert/AlertConfig.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/alert/Glucose.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/alert/Glucose.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/alert/Glucose.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/alert/Glucose.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/auth/GroupPermissions.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/auth/GroupPermissions.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/auth/GroupPermissions.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/auth/GroupPermissions.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/auth/ModifyUserPermissionsRequest.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/auth/ModifyUserPermissionsRequest.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/auth/ModifyUserPermissionsRequest.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/auth/ModifyUserPermissionsRequest.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/auth/TokenResponse.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/auth/TokenResponse.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/auth/TokenResponse.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/auth/TokenResponse.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/blob/BlobMetadata.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/blob/BlobMetadata.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/blob/BlobMetadata.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/blob/BlobMetadata.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/blob/DeviceLogsMetadata.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/blob/DeviceLogsMetadata.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/blob/DeviceLogsMetadata.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/blob/DeviceLogsMetadata.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/clinic/Clinic.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Clinic.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/clinic/Clinic.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Clinic.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/clinic/Clinician.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Clinician.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/clinic/Clinician.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Clinician.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/clinic/Patient.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Patient.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/clinic/Patient.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Patient.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/clinic/PatientTag.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/PatientTag.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/clinic/PatientTag.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/PatientTag.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/clinic/PhoneNumbers.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/PhoneNumbers.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/clinic/PhoneNumbers.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/PhoneNumbers.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/clinic/Site.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Site.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/clinic/Site.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/Site.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/clinic/SuppressedNotifications.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/SuppressedNotifications.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/clinic/SuppressedNotifications.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/clinic/SuppressedNotifications.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/confirmation/Confirmation.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/Confirmation.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/confirmation/Confirmation.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/Confirmation.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/confirmation/ConfirmationLookup.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/ConfirmationLookup.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/confirmation/ConfirmationLookup.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/ConfirmationLookup.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/confirmation/ConfirmationStatus.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/ConfirmationStatus.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/confirmation/ConfirmationStatus.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/ConfirmationStatus.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/confirmation/ConfirmationType.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/ConfirmationType.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/confirmation/ConfirmationType.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/ConfirmationType.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/confirmation/Restrictions.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/Restrictions.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/confirmation/Restrictions.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmation/Restrictions.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/confirmations/Acceptance.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmations/Acceptance.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/confirmations/Acceptance.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/confirmations/Acceptance.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/BasalAutomatedData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BasalAutomatedData.kt similarity index 96% rename from domain/src/main/java/org/tidepool/sdk/model/data/BasalAutomatedData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BasalAutomatedData.kt index 31209e0..ba5e63a 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/BasalAutomatedData.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BasalAutomatedData.kt @@ -17,7 +17,7 @@ data class BasalAutomatedData( override val deviceTime: String? = null, override val notes: List = emptyList(), override val timeZone: TimeZone? = null, - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, val deliveryType: DeliveryType, val duration: Int, val expectedDuration: Int? = null, diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/BaseData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BaseData.kt similarity index 94% rename from domain/src/main/java/org/tidepool/sdk/model/data/BaseData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BaseData.kt index 3979d59..916208d 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/BaseData.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BaseData.kt @@ -18,7 +18,7 @@ sealed class BaseData( open val deviceTime: String? = null, open val notes: List = emptyList(), open val timeZone: TimeZone? = null, - open val timeZoneOffset: Duration? = null, + open val timeZoneOffset: Int? = null, ) { val location: Nothing diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/BolusData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BolusData.kt similarity index 96% rename from domain/src/main/java/org/tidepool/sdk/model/data/BolusData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BolusData.kt index 0983099..b7f7d52 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/BolusData.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/BolusData.kt @@ -19,7 +19,7 @@ data class BolusData( override val deviceTime: String? = null, override val notes: List = emptyList(), override val timeZone: TimeZone? = null, - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, val subType: BolusSubtype = BolusSubtype.Normal, val deliveryContext: DeliveryContext, ) : BaseData( diff --git a/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/CgmSettingsData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/CgmSettingsData.kt new file mode 100644 index 0000000..1445fa4 --- /dev/null +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/CgmSettingsData.kt @@ -0,0 +1,34 @@ +package org.tidepool.sdk.model.data + +import org.tidepool.sdk.model.Association +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +data class CgmSettingsData( + override val id: String, + override val type: DataType = DataType.CgmSettings, + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + override val clockDriftOffset: Duration? = null, + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + override val timeZone: TimeZone? = null, + override val timeZoneOffset: Int? = null, +) : BaseData( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/ContinuousGlucoseData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/ContinuousGlucoseData.kt similarity index 94% rename from domain/src/main/java/org/tidepool/sdk/model/data/ContinuousGlucoseData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/ContinuousGlucoseData.kt index cfa9639..74d2bee 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/ContinuousGlucoseData.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/ContinuousGlucoseData.kt @@ -9,7 +9,7 @@ import kotlin.time.Duration data class ContinuousGlucoseData( override val id: String, - override val type: DataType = DataType.Alert, + override val type: DataType = DataType.Cbg, override val time: Instant? = null, override val annotations: List> = emptyList(), override val associations: List = emptyList(), @@ -19,7 +19,7 @@ data class ContinuousGlucoseData( override val deviceTime: String? = null, override val notes: List = emptyList(), override val timeZone: TimeZone? = null, - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, val value: Double? = null, val units: BloodGlucose.Units? = null, val trend: BloodGlucose.Trend? = null, diff --git a/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/ControllerSettingsData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/ControllerSettingsData.kt new file mode 100644 index 0000000..6c26a1a --- /dev/null +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/ControllerSettingsData.kt @@ -0,0 +1,34 @@ +package org.tidepool.sdk.model.data + +import org.tidepool.sdk.model.Association +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +data class ControllerSettingsData( + override val id: String, + override val type: DataType = DataType.ControllerSettings, + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + override val clockDriftOffset: Duration? = null, + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + override val timeZone: TimeZone? = null, + override val timeZoneOffset: Int? = null, +) : BaseData( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/DataSet.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DataSet.kt similarity index 88% rename from domain/src/main/java/org/tidepool/sdk/model/data/DataSet.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DataSet.kt index 312a66a..6b97af8 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/DataSet.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DataSet.kt @@ -20,7 +20,7 @@ data class DataSet( val deviceManufacturers: List? = null, val deviceModel: String? = null, val deviceSerialNumber: String? = null, - val deviceTags: List? = null, + val deviceTags: List? = null, val id: String? = null, val modifiedTime: Instant? = null, val modifiedUserId: String? = null, @@ -28,7 +28,7 @@ data class DataSet( val time: Instant? = null, val timeProcessing: String? = null, val timezone: String? = null, - val timezoneOffset: Duration? = null, + val timeZoneOffset: Int? = null, val type: String? = null, val uploadId: String? = null, val version: String? = null @@ -51,10 +51,16 @@ data class NewDataSet( val deviceManufacturers: List? = null, val deviceModel: String? = null, val deviceSerialNumber: String? = null, - val deviceTags: List? = null, + val deviceTags: List? = null, val deduplicator: DeduplicatorDescriptor? = null, val time: Instant? = null, val timeProcessing: String? = null, val timezone: String? = null, - val timezoneOffset: Duration? = null -) \ No newline at end of file + val timeZoneOffset: Int? = null +) + +enum class DeviceTag { + Bgm, + Cgm, + InsulinPump, +} \ No newline at end of file diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/DataSource.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DataSource.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/data/DataSource.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DataSource.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/DataType.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DataType.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/data/DataType.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DataType.kt diff --git a/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DeviceEventData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DeviceEventData.kt new file mode 100644 index 0000000..59ad9a5 --- /dev/null +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DeviceEventData.kt @@ -0,0 +1,51 @@ +package org.tidepool.sdk.model.data + +import org.tidepool.sdk.model.Association +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +/** + * Generic device event datum (e.g., CGM sensor/transmitter lifecycle events). + */ +data class DeviceEventData( + override val id: String, + override val type: DataType = DataType.DeviceEvent, + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + override val clockDriftOffset: Duration? = null, + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + override val timeZone: TimeZone? = null, + override val timeZoneOffset: Int? = null, + val subType: SubType, + val deviceIdentifier: String? = null, + /** seconds */ + val expectedLifetimeSeconds: Double? = null, + /** seconds */ + val warmupPeriodSeconds: Double? = null, + val failureMessage: String? = null, +) : BaseData( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) { + enum class SubType { + SensorStart, + SensorEnd, + TransmitterStart, + TransmitterEnd, + } +} diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/DosingDecisionData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DosingDecisionData.kt similarity index 96% rename from domain/src/main/java/org/tidepool/sdk/model/data/DosingDecisionData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DosingDecisionData.kt index 463e805..a952d3d 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/DosingDecisionData.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/DosingDecisionData.kt @@ -9,7 +9,7 @@ import kotlin.time.Duration // TODO: finish implementing dosingdecision.v1 data class DosingDecisionData( override val id: String, - override val type: DataType = DataType.Alert, + override val type: DataType = DataType.DosingDecision, override val time: Instant? = null, override val annotations: List> = emptyList(), override val associations: List = emptyList(), @@ -19,7 +19,7 @@ data class DosingDecisionData( override val deviceTime: String? = null, override val notes: List = emptyList(), override val timeZone: TimeZone? = null, - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, val reason: String, val carbsOnBoard: CarbsOnBoard? = null, val insulinOnBoard: InsulinOnBoard? = null, diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/FoodData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/FoodData.kt similarity index 96% rename from domain/src/main/java/org/tidepool/sdk/model/data/FoodData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/FoodData.kt index 6a4aa26..7f2c907 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/FoodData.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/FoodData.kt @@ -18,7 +18,7 @@ data class FoodData( override val deviceTime: String? = null, override val notes: List = emptyList(), override val timeZone: TimeZone? = null, - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, val brand: String? = null, val code: String? = null, val meal: Meal? = null, diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/Insulin.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/Insulin.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/data/Insulin.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/Insulin.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/data/InsulinData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/InsulinData.kt similarity index 96% rename from domain/src/main/java/org/tidepool/sdk/model/data/InsulinData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/InsulinData.kt index 7bcc5c9..a03cb1b 100644 --- a/domain/src/main/java/org/tidepool/sdk/model/data/InsulinData.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/InsulinData.kt @@ -18,7 +18,7 @@ data class InsulinData( override val deviceTime: String? = null, override val notes: List = emptyList(), override val timeZone: TimeZone? = null, - override val timeZoneOffset: Duration? = null, + override val timeZoneOffset: Int? = null, val dose: Dose, val site: String? ) : BaseData( diff --git a/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/PumpSettingsData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/PumpSettingsData.kt new file mode 100644 index 0000000..afed15c --- /dev/null +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/data/PumpSettingsData.kt @@ -0,0 +1,34 @@ +package org.tidepool.sdk.model.data + +import org.tidepool.sdk.model.Association +import java.time.Instant +import java.util.TimeZone +import kotlin.time.Duration + +data class PumpSettingsData( + override val id: String, + override val type: DataType = DataType.PumpSettings, + override val time: Instant? = null, + override val annotations: List> = emptyList(), + override val associations: List = emptyList(), + override val clockDriftOffset: Duration? = null, + override val conversionOffset: Duration? = null, + override val dataSetId: String? = null, + override val deviceTime: String? = null, + override val notes: List = emptyList(), + override val timeZone: TimeZone? = null, + override val timeZoneOffset: Int? = null, +) : BaseData( + id = id, + type = type, + time = time, + annotations = annotations, + associations = associations, + clockDriftOffset = clockDriftOffset, + conversionOffset = conversionOffset, + dataSetId = dataSetId, + deviceTime = deviceTime, + notes = notes, + timeZone = timeZone, + timeZoneOffset = timeZoneOffset, +) diff --git a/domain/src/main/java/org/tidepool/sdk/model/export/ExportData.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/export/ExportData.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/export/ExportData.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/export/ExportData.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/export/ExportFormat.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/export/ExportFormat.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/export/ExportFormat.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/export/ExportFormat.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/general/MinimumClientVersions.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/general/MinimumClientVersions.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/general/MinimumClientVersions.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/general/MinimumClientVersions.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/messages/Message.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/messages/Message.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/messages/Message.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/messages/Message.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/metadata/MetadataCollection.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/MetadataCollection.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/metadata/MetadataCollection.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/MetadataCollection.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/metadata/Profile.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/Profile.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/metadata/Profile.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/Profile.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/metadata/UserProfile.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/UserProfile.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/metadata/UserProfile.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/UserProfile.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/metadata/users/Permission.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/users/Permission.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/metadata/users/Permission.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/users/Permission.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/metadata/users/TrustUser.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/users/TrustUser.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/metadata/users/TrustUser.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/users/TrustUser.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/metadata/users/User.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/users/User.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/metadata/users/User.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/metadata/users/User.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/prescription/NewPrescription.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/NewPrescription.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/prescription/NewPrescription.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/NewPrescription.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/prescription/Prescription.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/Prescription.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/prescription/Prescription.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/Prescription.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/prescription/PrescriptionStatus.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/PrescriptionStatus.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/prescription/PrescriptionStatus.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/PrescriptionStatus.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/prescription/UpdatePrescription.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/UpdatePrescription.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/prescription/UpdatePrescription.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/prescription/UpdatePrescription.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/summary/GlucoseRange.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/GlucoseRange.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/summary/GlucoseRange.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/GlucoseRange.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/summary/Summary.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/Summary.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/summary/Summary.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/Summary.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/summary/SummaryConfig.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/SummaryConfig.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/summary/SummaryConfig.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/SummaryConfig.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/summary/SummaryDates.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/SummaryDates.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/summary/SummaryDates.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/SummaryDates.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/summary/SummaryType.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/SummaryType.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/summary/SummaryType.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/summary/SummaryType.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/task/Task.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/task/Task.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/task/Task.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/task/Task.kt diff --git a/domain/src/main/java/org/tidepool/sdk/model/task/TaskState.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/model/task/TaskState.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/model/task/TaskState.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/model/task/TaskState.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/AlertRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/AlertRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/AlertRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/AlertRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/AuthorizationRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/AuthorizationRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/AuthorizationRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/AuthorizationRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/BlobRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/BlobRepository.kt similarity index 80% rename from domain/src/main/java/org/tidepool/sdk/repository/BlobRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/BlobRepository.kt index 6ae2cbe..03e8c33 100644 --- a/domain/src/main/java/org/tidepool/sdk/repository/BlobRepository.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/BlobRepository.kt @@ -16,13 +16,13 @@ interface BlobRepository { sessionToken: String ): Result> - suspend fun createBlob( - userId: String, - contentType: String, - digest: String, - content: ByteArray, - sessionToken: String - ): Result +// suspend fun createBlob( +// userId: String, +// contentType: String, +// digest: String, +// content: ByteArray, +// sessionToken: String +// ): Result suspend fun deleteAllBlobs( userId: String, @@ -39,10 +39,10 @@ interface BlobRepository { sessionToken: String ): Result - suspend fun getBlobContent( - blobId: String, - sessionToken: String - ): Result +// suspend fun getBlobContent( +// blobId: String, +// sessionToken: String +// ): Result // Device logs operations suspend fun uploadDeviceLogs( diff --git a/domain/src/main/java/org/tidepool/sdk/repository/ClinicRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/ClinicRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/ClinicRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/ClinicRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/ConfirmationRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/ConfirmationRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/ConfirmationRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/ConfirmationRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/DataRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/DataRepository.kt similarity index 89% rename from domain/src/main/java/org/tidepool/sdk/repository/DataRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/DataRepository.kt index 6c64380..6393fa4 100644 --- a/domain/src/main/java/org/tidepool/sdk/repository/DataRepository.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/DataRepository.kt @@ -10,6 +10,15 @@ import java.time.Instant interface DataRepository { + /** + * Returns the cached data set id if available. If not available, ensures that at most one + * coroutine performs the discovery/creation via [create], while all other callers wait for + * the result. This provides a three-state behavior: Uninitialized, Loading, and Ready. + */ + suspend fun awaitOrCreateCachedDataSetId( + create: suspend () -> Result, + ): Result + suspend fun getDataForUser( userId: String, uploadId: String? = null, @@ -138,12 +147,6 @@ interface DataRepository { sessionToken: String ): Result - suspend fun uploadData( - userId: String, - data: List, - sessionToken: String - ): Result> - suspend fun uploadCachedData( userId: String, sessionToken: String, diff --git a/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/ExportRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/ExportRepository.kt new file mode 100644 index 0000000..a683c1a --- /dev/null +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/ExportRepository.kt @@ -0,0 +1,18 @@ +package org.tidepool.sdk.repository + +import org.tidepool.sdk.model.BloodGlucose +import org.tidepool.sdk.model.export.ExportData +import org.tidepool.sdk.model.export.ExportFormat +import java.time.Instant + +interface ExportRepository { + +// suspend fun exportUserData( +// sessionToken: String, +// userId: String, +// startDate: Instant? = null, +// endDate: Instant? = null, +// bgUnits: BloodGlucose.Units = BloodGlucose.Units.MillimolesPerLiter, +// format: ExportFormat, +// ): Result +} \ No newline at end of file diff --git a/domain/src/main/java/org/tidepool/sdk/repository/GeneralRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/GeneralRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/GeneralRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/GeneralRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/MessageRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/MessageRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/MessageRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/MessageRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/MetadataRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/MetadataRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/MetadataRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/MetadataRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/MetricsRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/MetricsRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/MetricsRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/MetricsRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/PrescriptionRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/PrescriptionRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/PrescriptionRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/PrescriptionRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/SummaryRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/SummaryRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/SummaryRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/SummaryRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/TaskRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/TaskRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/TaskRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/TaskRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/UserRepository.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/repository/UserRepository.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/repository/UserRepository.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/repository/UserRepository.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/AlertService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/AlertService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/AlertService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/AlertService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/AuthorizationService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/AuthorizationService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/AuthorizationService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/AuthorizationService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/BlobService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/BlobService.kt similarity index 78% rename from domain/src/main/java/org/tidepool/sdk/service/BlobService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/BlobService.kt index 214f8ba..d3bbdc3 100644 --- a/domain/src/main/java/org/tidepool/sdk/service/BlobService.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/BlobService.kt @@ -28,20 +28,20 @@ class BlobService internal constructor( ) } - suspend fun createBlob( - userId: String, - contentType: String, - digest: String, - content: ByteArray - ): Result = tokenProvider.getToken().flatMap { - blobRepository.createBlob( - userId = userId, - contentType = contentType, - digest = digest, - content = content, - sessionToken = it, - ) - } +// suspend fun createBlob( +// userId: String, +// contentType: String, +// digest: String, +// content: ByteArray +// ): Result = tokenProvider.getToken().flatMap { +// blobRepository.createBlob( +// userId = userId, +// contentType = contentType, +// digest = digest, +// content = content, +// sessionToken = it, +// ) +// } suspend fun deleteAllBlobs(userId: String): Result = tokenProvider.getToken().flatMap { blobRepository.deleteAllBlobs( @@ -65,13 +65,13 @@ class BlobService internal constructor( ) } - suspend fun getBlobContent(blobId: String): Result = - tokenProvider.getToken().flatMap { - blobRepository.getBlobContent( - blobId = blobId, - sessionToken = it, - ) - } +// suspend fun getBlobContent(blobId: String): Result = +// tokenProvider.getToken().flatMap { +// blobRepository.getBlobContent( +// blobId = blobId, +// sessionToken = it, +// ) +// } // Device logs operations suspend fun uploadDeviceLogs( diff --git a/domain/src/main/java/org/tidepool/sdk/service/ClinicService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/ClinicService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/ClinicService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/ClinicService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/ConfirmationService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/ConfirmationService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/ConfirmationService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/ConfirmationService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/DataService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/DataService.kt similarity index 74% rename from domain/src/main/java/org/tidepool/sdk/service/DataService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/DataService.kt index 2c98bd2..de328be 100644 --- a/domain/src/main/java/org/tidepool/sdk/service/DataService.kt +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/DataService.kt @@ -7,9 +7,12 @@ import org.tidepool.sdk.PaginatorImpl import org.tidepool.sdk.TokenProvider import org.tidepool.sdk.flatMap import org.tidepool.sdk.model.data.BaseData +import org.tidepool.sdk.model.data.ClientSoftware import org.tidepool.sdk.model.data.DataSet import org.tidepool.sdk.model.data.DataSource import org.tidepool.sdk.model.data.DataType +import org.tidepool.sdk.model.data.DeduplicatorDescriptor +import org.tidepool.sdk.model.data.DeviceTag import org.tidepool.sdk.model.data.NewDataSet import org.tidepool.sdk.model.data.NewDataSource import org.tidepool.sdk.repository.DataRepository @@ -17,13 +20,15 @@ import org.tidepool.sdk.repository.UserRepository import kotlin.time.Duration import java.time.Instant import java.util.Collections.emptyList +import java.util.TimeZone +import kotlin.time.Duration.Companion.milliseconds class DataService internal constructor( private val dataRepository: DataRepository, private val userRepository: UserRepository, private val tokenProvider: TokenProvider, ) { - + fun startLifecycleAwareRecurrentUpload( lifecycleProvider: AppLifecycleProvider, scope: CoroutineScope, @@ -47,7 +52,7 @@ class DataService internal constructor( ) start() } - + suspend fun getDataForUser( userId: String, uploadId: String? = null, @@ -74,7 +79,7 @@ class DataService internal constructor( sessionToken = it, ) } - + // Data Sets operations suspend fun getUserDataSets(userId: String): Result> = tokenProvider.getToken().flatMap { @@ -83,7 +88,17 @@ class DataService internal constructor( sessionToken = it, ) } - + + suspend fun getUserDataSets(): Result> = + tokenProvider.getToken().flatMap { token -> + userRepository.getCurrentUser(token).flatMap { user -> + dataRepository.getUserDataSets( + userId = user.userId, + sessionToken = token, + ) + } + } + // Data Sets operations suspend fun getUserDataSetsPaginator( userId: String, @@ -107,7 +122,7 @@ class DataService internal constructor( onFailure = onPageLoadFailure, endReached = { page, _ -> page.size < pageSize } ) - + suspend fun createDataSet(userId: String, newDataSet: NewDataSet): Result = tokenProvider.getToken().flatMap { dataRepository.createDataSet( @@ -116,7 +131,20 @@ class DataService internal constructor( sessionToken = it, ) } - + + suspend fun createDataSet(newDataSet: NewDataSet): Result = + tokenProvider.getToken().flatMap { token -> + println("DataService: Creating data set with token: ${token.take(5)}...") + userRepository.getCurrentUser(token).flatMap { user -> + println("DataService: Creating data set for user: ${user.userId}") + dataRepository.createDataSet( + userId = user.userId, + newDataSet = newDataSet, + sessionToken = token, + ) + } + } + suspend fun getDataSet(dataSetId: String): Result = tokenProvider.getToken().flatMap { dataRepository.getDataSet( @@ -124,7 +152,7 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun updateDataSet(dataSetId: String, dataSet: DataSet): Result = tokenProvider.getToken().flatMap { dataRepository.updateDataSet( @@ -133,7 +161,7 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun deleteDataSet(dataSetId: String): Result = tokenProvider.getToken().flatMap { dataRepository.deleteDataSet( @@ -141,19 +169,20 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun uploadDataToDataSet( dataSetId: String, - data: List + data: List, ): Result> = tokenProvider.getToken().flatMap { + println("DataService: Uploading data to data set $dataSetId") dataRepository.uploadDataToDataSet( dataSetId = dataSetId, data = data, sessionToken = it, ) } - + suspend fun deleteDataSetData(dataSetId: String): Result = tokenProvider.getToken().flatMap { dataRepository.deleteDataSetData( @@ -161,7 +190,7 @@ class DataService internal constructor( sessionToken = it, ) } - + // Legacy datasets operations @Deprecated("Use getUserDataSets instead", ReplaceWith("getUserDataSets")) suspend fun getUserDataSetsLegacy(userId: String): Result> = @@ -171,7 +200,7 @@ class DataService internal constructor( sessionToken = it, ) } - + @Deprecated("Use createDataSet instead", ReplaceWith("createDataSet")) suspend fun createDataSetLegacy(userId: String, newDataSet: NewDataSet): Result = tokenProvider.getToken().flatMap { @@ -181,7 +210,7 @@ class DataService internal constructor( sessionToken = it, ) } - + @Deprecated("Use getDataSet instead", ReplaceWith("getDataSet")) suspend fun getDataSetLegacy(dataSetId: String): Result = tokenProvider.getToken().flatMap { @@ -190,7 +219,7 @@ class DataService internal constructor( sessionToken = it, ) } - + @Deprecated("Use updateDataSet instead", ReplaceWith("updateDataSet")) suspend fun updateDataSetLegacy(dataSetId: String, dataSet: DataSet): Result = tokenProvider.getToken().flatMap { @@ -200,7 +229,7 @@ class DataService internal constructor( sessionToken = it, ) } - + @Deprecated("Use deleteDataSet instead", ReplaceWith("deleteDataSet")) suspend fun deleteDataSetLegacy(dataSetId: String): Result = tokenProvider.getToken().flatMap { @@ -209,11 +238,11 @@ class DataService internal constructor( sessionToken = it, ) } - + @Deprecated("Use uploadDataToDataSet instead", ReplaceWith("uploadDataToDataSet")) suspend fun uploadDataToDataSetLegacy( dataSetId: String, - data: List + data: List, ): Result> = tokenProvider.getToken().flatMap { dataRepository.uploadDataToDataSetLegacy( @@ -222,7 +251,7 @@ class DataService internal constructor( sessionToken = it, ) } - + // Data Sources operations suspend fun getUserDataSources(userId: String): Result> = tokenProvider.getToken().flatMap { @@ -231,7 +260,7 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun getUserDataSourcesPaginator( userId: String, pageSize: Int = 42, @@ -252,7 +281,7 @@ class DataService internal constructor( onFailure = onPageLoadFailure, endReached = { page, _ -> page.size < pageSize }, ) - + suspend fun createDataSource(userId: String, newDataSource: NewDataSource): Result = tokenProvider.getToken().flatMap { dataRepository.createDataSource( @@ -261,7 +290,7 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun deleteAllDataSources(userId: String): Result = tokenProvider.getToken().flatMap { dataRepository.deleteAllDataSources( @@ -269,7 +298,7 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun getDataSource(dataSourceId: String): Result = tokenProvider.getToken().flatMap { dataRepository.getDataSource( @@ -277,7 +306,7 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun updateDataSource(dataSourceId: String, dataSource: DataSource): Result = tokenProvider.getToken().flatMap { dataRepository.updateDataSource( @@ -286,7 +315,7 @@ class DataService internal constructor( sessionToken = it, ) } - + suspend fun deleteDataSource(dataSourceId: String): Result = tokenProvider.getToken().flatMap { dataRepository.deleteDataSource( @@ -294,7 +323,7 @@ class DataService internal constructor( sessionToken = it, ) } - + // Additional data operations suspend fun deleteAllUserData(userId: String): Result = tokenProvider.getToken().flatMap { @@ -303,13 +332,57 @@ class DataService internal constructor( sessionToken = it, ) } - - suspend fun uploadData(userId: String, data: List): Result> = - tokenProvider.getToken().flatMap { - dataRepository.uploadData( - userId = userId, + + suspend fun uploadData(data: List): Result> = + getDataSetId().flatMap { dataSetId -> + uploadDataToDataSet( + dataSetId = dataSetId, data = data, - sessionToken = it, ) } + + suspend fun uploadData(data: BaseData): Result> = uploadData(listOf(data)) + + private suspend fun getDataSetId() = dataRepository.awaitOrCreateCachedDataSetId { + getUserDataSets() + .flatMap { dataSets -> + dataSets + .filter { it.uploadId != null } + .minByOrNull { it.uploadId!! } + ?.let { + println("DataService: Found existing data set with id: ${it.id}") + Result.success(it) + } + ?: createDataSet( + newDataSet = NewDataSet( + client = ClientSoftware( + name = "org.tidepool.loop", + version = "TEST", + ), + dataSetType = "continuous", + timezone = TimeZone.getDefault().id, + timeZoneOffset = TimeZone.getDefault().rawOffset.milliseconds.inWholeMinutes.toInt(), + deviceManufacturers = listOf( + "test" + ), + deviceId = "test", + time = Instant.now(), + deduplicator = DeduplicatorDescriptor( + name = "org.tidepool.deduplicator.dataset.delete.origin", + ), + deviceTags = listOf( + DeviceTag.Bgm, + DeviceTag.Cgm, + DeviceTag.InsulinPump, + ), + deviceSerialNumber = "test", + timeProcessing = "none", + ), + ) + }.flatMap { + println("DataService: Created data set: ${it.id}") + it.id?.let { Result.success(it) } + ?: Result.failure(IllegalStateException("No id")) + } + } } \ No newline at end of file diff --git a/domain/src/commonMain/kotlin/org/tidepool/sdk/service/ExportService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/ExportService.kt new file mode 100644 index 0000000..178a5cd --- /dev/null +++ b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/ExportService.kt @@ -0,0 +1,35 @@ +package org.tidepool.sdk.service + +import org.tidepool.sdk.TokenProvider +import org.tidepool.sdk.flatMap +import org.tidepool.sdk.model.BloodGlucose +import org.tidepool.sdk.model.export.ExportData +import org.tidepool.sdk.model.export.ExportFormat +import org.tidepool.sdk.repository.ExportRepository +import org.tidepool.sdk.repository.UserRepository +import java.time.Instant + +class ExportService internal constructor( + private val exportRepository: ExportRepository, + private val tokenProvider: TokenProvider, + private val userRepository: UserRepository, +) { + +// suspend fun exportUserData( +// startDate: Instant? = null, +// endDate: Instant? = null, +// format: ExportFormat = ExportFormat.Xlsx, +// bgUnits: BloodGlucose.Units = BloodGlucose.Units.MillimolesPerLiter, +// ): Result = tokenProvider.getToken().flatMap { token -> +// userRepository.getCurrentUser(sessionToken = token).flatMap { user -> +// exportRepository.exportUserData( +// sessionToken = token, +// userId = user.userId, +// startDate = startDate, +// endDate = endDate, +// bgUnits = bgUnits, +// format = format, +// ) +// } +// } +} \ No newline at end of file diff --git a/domain/src/main/java/org/tidepool/sdk/service/GeneralService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/GeneralService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/GeneralService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/GeneralService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/LifecycleAwareDataUploadManager.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/LifecycleAwareDataUploadManager.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/LifecycleAwareDataUploadManager.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/LifecycleAwareDataUploadManager.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/MessageService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/MessageService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/MessageService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/MessageService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/MetadataService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/MetadataService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/MetadataService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/MetadataService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/MetricsService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/MetricsService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/MetricsService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/MetricsService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/PrescriptionService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/PrescriptionService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/PrescriptionService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/PrescriptionService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/SummaryService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/SummaryService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/SummaryService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/SummaryService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/TaskService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/TaskService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/TaskService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/TaskService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/service/UserService.kt b/domain/src/commonMain/kotlin/org/tidepool/sdk/service/UserService.kt similarity index 100% rename from domain/src/main/java/org/tidepool/sdk/service/UserService.kt rename to domain/src/commonMain/kotlin/org/tidepool/sdk/service/UserService.kt diff --git a/domain/src/main/java/org/tidepool/sdk/repository/ExportRepository.kt b/domain/src/main/java/org/tidepool/sdk/repository/ExportRepository.kt deleted file mode 100644 index 377e771..0000000 --- a/domain/src/main/java/org/tidepool/sdk/repository/ExportRepository.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.tidepool.sdk.repository - -import org.tidepool.sdk.model.BloodGlucose -import org.tidepool.sdk.model.export.ExportData -import org.tidepool.sdk.model.export.ExportFormat -import java.time.Instant - -interface ExportRepository { - - suspend fun exportUserData( - sessionToken: String, - userId: String, - startDate: Instant? = null, - endDate: Instant? = null, - bgUnits: BloodGlucose.Units = BloodGlucose.Units.MillimolesPerLiter, - format: ExportFormat, - ): Result -} \ No newline at end of file diff --git a/domain/src/main/java/org/tidepool/sdk/service/ExportService.kt b/domain/src/main/java/org/tidepool/sdk/service/ExportService.kt deleted file mode 100644 index e2f6d45..0000000 --- a/domain/src/main/java/org/tidepool/sdk/service/ExportService.kt +++ /dev/null @@ -1,35 +0,0 @@ -package org.tidepool.sdk.service - -import org.tidepool.sdk.TokenProvider -import org.tidepool.sdk.flatMap -import org.tidepool.sdk.model.BloodGlucose -import org.tidepool.sdk.model.export.ExportData -import org.tidepool.sdk.model.export.ExportFormat -import org.tidepool.sdk.repository.ExportRepository -import org.tidepool.sdk.repository.UserRepository -import java.time.Instant - -class ExportService internal constructor( - private val exportRepository: ExportRepository, - private val tokenProvider: TokenProvider, - private val userRepository: UserRepository, -) { - - suspend fun exportUserData( - startDate: Instant? = null, - endDate: Instant? = null, - format: ExportFormat = ExportFormat.Xlsx, - bgUnits: BloodGlucose.Units = BloodGlucose.Units.MillimolesPerLiter, - ): Result = tokenProvider.getToken().flatMap { token -> - userRepository.getCurrentUser(sessionToken = token).flatMap { user -> - exportRepository.exportUserData( - sessionToken = token, - userId = user.userId, - startDate = startDate, - endDate = endDate, - bgUnits = bgUnits, - format = format, - ) - } - } -} \ No newline at end of file diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 8d33ca4..385fa9a 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -6,12 +6,24 @@ */ plugins { - // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - kotlin("jvm") + kotlin("multiplatform") kotlin("plugin.serialization") id("com.google.devtools.ksp") - // Apply the java-library plugin for API and implementation separation. - `java-library` + id("com.android.library") +} + +android { + namespace = "org.tidepool.sdk" + compileSdk = 34 + + defaultConfig { + minSdk = 26 + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } } repositories { @@ -21,49 +33,51 @@ repositories { } dependencies { - api(project(":TidepoolKotlinAPI:domain")) - implementation(project(":TidepoolKotlinAPI:data")) - - implementation("com.squareup.retrofit2:retrofit:3.0.0") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") - - // Kotlinx.serialization dependencies - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") - implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0") - - // OkHttp for MediaType - implementation("com.squareup.okhttp3:okhttp:5.1.0") - - // Room KMP dependencies - implementation("androidx.room:room-runtime:2.8.1") - implementation("androidx.sqlite:sqlite-bundled:2.5.0") - ksp("androidx.room:room-compiler:2.8.1") - - // Koin dependency injection - implementation("io.insert-koin:koin-core:4.1.0") - implementation("io.insert-koin:koin-annotations:2.1.0") - - // Use the Kotlin JUnit 5 integration. - testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") - - // Use the JUnit 5 integration. - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.2") - - // Koin testing - testImplementation("io.insert-koin:koin-test:4.1.0") - testImplementation("io.insert-koin:koin-test-junit5:4.1.0") - - testRuntimeOnly("org.junit.platform:junit-platform-launcher") + add("kspCommonMainMetadata", "androidx.room:room-compiler:2.8.1") } -// Apply a specific Java toolchain to ease working on different environments. -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) +kotlin { + androidTarget { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + } } -} -tasks.named("test") { - // Use JUnit Platform for unit tests. - useJUnitPlatform() -} + sourceSets { + val commonMain by getting { + dependencies { + api(project(":TidepoolKotlinAPI:domain")) + implementation(project(":TidepoolKotlinAPI:data")) + + implementation("com.squareup.retrofit2:retrofit:3.0.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") + + // Kotlinx.serialization dependencies + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") + implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0") + + // OkHttp for MediaType + implementation("com.squareup.okhttp3:okhttp:5.1.0") + + // Room KMP dependencies + implementation("androidx.room:room-runtime:2.8.1") + implementation("androidx.sqlite:sqlite-bundled:2.5.0") + + // Koin dependency injection + implementation("io.insert-koin:koin-core:4.1.0") + implementation("io.insert-koin:koin-annotations:2.1.0") + } + } + + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + // Koin testing + implementation("io.insert-koin:koin-test:4.1.0") + } + } + + val androidMain by getting + val androidUnitTest by getting + } +} \ No newline at end of file diff --git a/lib/src/androidMain/kotlin/org/tidepool/sdk/TidepoolSDK.android.kt b/lib/src/androidMain/kotlin/org/tidepool/sdk/TidepoolSDK.android.kt new file mode 100644 index 0000000..b462b47 --- /dev/null +++ b/lib/src/androidMain/kotlin/org/tidepool/sdk/TidepoolSDK.android.kt @@ -0,0 +1,16 @@ +package org.tidepool.sdk + +import android.content.Context +import org.koin.dsl.module + +public fun TidepoolSDK.Companion.create( + environment: Environment, + tokenProvider: TokenProvider, + context: Context, +) = TidepoolSDK( + environment = environment, + tokenProvider = tokenProvider, + platformModule = module { + single { context } + }, +) \ No newline at end of file diff --git a/lib/src/main/kotlin/org/tidepool/sdk/TidepoolSDK.kt b/lib/src/commonMain/kotlin/org/tidepool/sdk/TidepoolSDK.kt similarity index 81% rename from lib/src/main/kotlin/org/tidepool/sdk/TidepoolSDK.kt rename to lib/src/commonMain/kotlin/org/tidepool/sdk/TidepoolSDK.kt index 4795e59..4dd5987 100644 --- a/lib/src/main/kotlin/org/tidepool/sdk/TidepoolSDK.kt +++ b/lib/src/commonMain/kotlin/org/tidepool/sdk/TidepoolSDK.kt @@ -1,11 +1,12 @@ package org.tidepool.sdk import org.koin.core.Koin -import org.koin.core.module.dsl.singleOf +import org.koin.core.module.Module import org.koin.dsl.koinApplication import org.koin.dsl.module import org.tidepool.sdk.di.dataModule import org.tidepool.sdk.di.domainModule +import org.tidepool.sdk.di.platformDataModule import org.tidepool.sdk.service.AlertService import org.tidepool.sdk.service.AuthorizationService import org.tidepool.sdk.service.BlobService @@ -22,10 +23,19 @@ import org.tidepool.sdk.service.SummaryService import org.tidepool.sdk.service.TaskService import org.tidepool.sdk.service.UserService -class TidepoolSDK( +//// Public factory function - expect/actual pattern +//expect fun createTidepoolSDK( +// environment: Environment, +// tokenProvider: TokenProvider, +//): TidepoolSDK + +class TidepoolSDK internal constructor( val environment: Environment, private val tokenProvider: TokenProvider, + private val platformModule: Module = module {}, ) { + + companion object {} // Internal DI container - not exposed @@ -35,9 +45,12 @@ class TidepoolSDK( module { single { environment } single { tokenProvider } + // Provide Android context if available (for Android platform) }, domainModule, dataModule, + platformDataModule, + platformModule, ) } private val koin: Koin = koinApp.koin diff --git a/lib/src/test/kotlin/org/tidepool/sdk/auth/AuthSerializationTest.kt b/lib/src/test/kotlin/org/tidepool/sdk/auth/AuthSerializationTest.kt deleted file mode 100644 index cff021c..0000000 --- a/lib/src/test/kotlin/org/tidepool/sdk/auth/AuthSerializationTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.tidepool.sdk.auth - -import kotlinx.serialization.json.Json -import kotlin.test.Test -import kotlin.test.assertEquals - -class AuthSerializationTest { - - private val json: Json by CommunicationHelper.Companion::jsonConfig - - @Test - fun serializationTest() { - val req = TokenRequest( - GrantType.Password, - "cgm-monitor", - client_secret = "c50e6502-131c-47f0-b439-a43acb3b83d0", - password = "qwertyuiop1234", - username = "user@example.com" - ) - val serialized = json.encodeToString(req) - val expectedJson = - "{\"grant_type\":\"password\",\"client_id\":\"cgm-monitor\",\"client_secret\":\"c50e6502-131c-47f0-b439-a43acb3b83d0\",\"subject_token\":null,\"subject_token_type\":null,\"requested_token_type\":null,\"subject_issuer\":null,\"username\":\"user@example.com\",\"password\":\"qwertyuiop1234\",\"code\":null,\"code_verifier\":null}" - assertEquals(expectedJson, serialized) - assertEquals(req, json.decodeFromString(serialized)) - } - - - @Test - fun serializationAnnotationTest() { - val req = TokenRequest(GrantType.TokenExchange, "cgm-monitor") - val serialized = json.encodeToString(req) - val expectedJson = - "{\"grant_type\":\"urn:ietf:params:oauth:grant-type:token-exchange\",\"client_id\":\"cgm-monitor\",\"client_secret\":null,\"subject_token\":null,\"subject_token_type\":null,\"requested_token_type\":null,\"subject_issuer\":null,\"username\":null,\"password\":null,\"code\":null,\"code_verifier\":null}" - assertEquals(expectedJson, serialized) - assertEquals(req, json.decodeFromString(serialized)) - } -} \ No newline at end of file diff --git a/lib/src/test/kotlin/org/tidepool/sdk/deserialization/DeserializationTest.kt b/lib/src/test/kotlin/org/tidepool/sdk/deserialization/DeserializationTest.kt deleted file mode 100644 index c1f92e3..0000000 --- a/lib/src/test/kotlin/org/tidepool/sdk/deserialization/DeserializationTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -package org.tidepool.sdk.deserialization - -import kotlinx.serialization.SerialName -import kotlinx.serialization.json.Json -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationException -import kotlin.reflect.KClass -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - -class DeserializationTest { - - @Serializable - sealed class Sample( - val type: SampleSubtype, - val id: String? = null - ) { - - @Serializable - enum class SampleSubtype(override val subclassType: KClass) : - ResultType { - - @SerialName("testSubclass") - TestSubclassType(TestSubclass::class), - - @SerialName("nullSubclass") - NullSubclass(Sample::class) - } - } - - @Serializable - data class TestSubclass(val name: String = "Test") : Sample(SampleSubtype.TestSubclassType, "id") - - val json: Json by lazy { - CommunicationHelper.jsonConfig - } - - @Test - fun deserializationTest() { - val subclassInstance = TestSubclass("Test") - val jsonString = json.encodeToString(subclassInstance) - val fromJson = json.decodeFromString(jsonString) - assertEquals(subclassInstance, fromJson) - } - - @Test - fun nullFail() { - // This test is no longer applicable since we're testing different serialization behavior - // With Kotlinx.serialization, the enum deserialization will either work or fail differently - // Let's test a more realistic failure case - val jsonString = "{\"name\":\"Test\",\"type\":\"unknownSubtype\",\"id\":\"id\"}" - val exception = assertFailsWith { - json.decodeFromString(jsonString) - } - // Kotlinx.serialization will throw when encountering unknown enum values - } -} \ No newline at end of file