diff --git a/app/build.gradle b/app/build.gradle index 04fb0b520d..8d71d287b1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -235,6 +235,7 @@ dependencies { wearApp project(':wear') implementation project(':core') + implementation project(':database') implementation project(':dana') implementation project(':danars') implementation project(':danar') diff --git a/build.gradle b/build.gradle index 977c6fe4ce..6f9baba6ee 100644 --- a/build.gradle +++ b/build.gradle @@ -2,12 +2,12 @@ buildscript { ext { - kotlin_version = '1.4.21' + kotlin_version = '1.4.30' coreVersion = '1.3.2' - rxjava_version = '2.2.19' + rxjava_version = '2.2.20' rxandroid_version = '2.1.1' rxkotlin_version = '2.4.0' - room_version = '2.2.5' + room_version = '2.2.6' lifecycle_version = '2.2.0' dagger_version = '2.31.2' coroutinesVersion = '1.3.7' diff --git a/database/.gitignore b/database/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/database/.gitignore @@ -0,0 +1 @@ +/build diff --git a/database/build.gradle b/database/build.gradle new file mode 100644 index 0000000000..5c86517f06 --- /dev/null +++ b/database/build.gradle @@ -0,0 +1,60 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 23 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + } + firebaseDisable { + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation "androidx.core:core-ktx:$coreVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation "io.reactivex.rxjava2:rxjava:$rxjava_version" + implementation "io.reactivex.rxjava2:rxandroid:$rxandroid_version" + implementation("io.reactivex.rxjava2:rxkotlin:$rxkotlin_version") + + implementation "com.google.code.gson:gson:2.8.6" + + api "androidx.room:room-runtime:$room_version" + kapt "androidx.room:room-compiler:$room_version" + implementation "androidx.room:room-ktx:$room_version" + implementation "androidx.room:room-rxjava2:$room_version" + + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + + implementation "com.google.dagger:dagger-android:$dagger_version" + implementation "com.google.dagger:dagger-android-support:$dagger_version" + annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version" + annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version" + kapt "com.google.dagger:dagger-android-processor:$dagger_version" + kapt "com.google.dagger:dagger-compiler:$dagger_version" +} diff --git a/database/consumer-rules.pro b/database/consumer-rules.pro new file mode 100644 index 0000000000..e69de29bb2 diff --git a/database/proguard-rules.pro b/database/proguard-rules.pro new file mode 100644 index 0000000000..f1b424510d --- /dev/null +++ b/database/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/database/src/androidTest/java/info/nightscout/database/ExampleInstrumentedTest.kt b/database/src/androidTest/java/info/nightscout/database/ExampleInstrumentedTest.kt new file mode 100644 index 0000000000..d218cd479f --- /dev/null +++ b/database/src/androidTest/java/info/nightscout/database/ExampleInstrumentedTest.kt @@ -0,0 +1,25 @@ +package info.nightscout.database + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("info.nightscout.database.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/database/src/main/AndroidManifest.xml b/database/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..fa796cae8a --- /dev/null +++ b/database/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt b/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt new file mode 100644 index 0000000000..ffe65a8bdc --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/AppDatabase.kt @@ -0,0 +1,55 @@ +package info.nightscout.androidaps.database + +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import info.nightscout.androidaps.database.daos.* +import info.nightscout.androidaps.database.entities.* +import info.nightscout.androidaps.database.entities.APSResultLink +import info.nightscout.androidaps.database.entities.MealLink +import info.nightscout.androidaps.database.entities.MultiwaveBolusLink + +const val DATABASE_VERSION = 1 + +@Database(version = DATABASE_VERSION, entities = arrayOf(APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class, + EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class, + TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, + APSResultLink::class, MealLink::class, MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class)) +@TypeConverters(Converters::class) +internal abstract class AppDatabase : RoomDatabase() { + + abstract val glucoseValueDao: GlucoseValueDao + + abstract val therapyEventDao: TherapyEventDao + + abstract val temporaryBasalDao: TemporaryBasalDao + + abstract val bolusDao: BolusDao + + abstract val extendedBolusDao: ExtendedBolusDao + + abstract val multiwaveBolusLinkDao: MultiwaveBolusLinkDao + + abstract val totalDailyDoseDao: TotalDailyDoseDao + + abstract val carbsDao: CarbsDao + + abstract val mealLinkDao: MealLinkDao + + abstract val temporaryTargetDao: TemporaryTargetDao + + abstract val apsResultLinkDao: APSResultLinkDao + + abstract val bolusCalculatorResultDao: BolusCalculatorResultDao + + abstract val effectiveProfileSwitchDao: EffectiveProfileSwitchDao + + abstract val profileSwitchDao: ProfileSwitchDao + + abstract val apsResultDao: APSResultDao + + abstract val versionChangeDao: VersionChangeDao + + abstract val preferenceChangeDao: PreferenceChangeDao + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt new file mode 100644 index 0000000000..0a13455b06 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/AppRepository.kt @@ -0,0 +1,118 @@ +package info.nightscout.androidaps.database + +import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.database.entities.TemporaryTarget +import info.nightscout.androidaps.database.interfaces.DBEntry +import info.nightscout.androidaps.database.transactions.Transaction +import io.reactivex.Completable +import io.reactivex.Maybe +import io.reactivex.Observable +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import io.reactivex.subjects.PublishSubject +import java.util.concurrent.Callable +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class AppRepository @Inject internal constructor( + internal val database: AppDatabase +) { + + private val changeSubject = PublishSubject.create>() + + fun changeObservable(): Observable> = changeSubject.subscribeOn(Schedulers.io()) + + val databaseVersion = DATABASE_VERSION + + /** + * Executes a transaction ignoring its result + * Runs on IO scheduler + */ + fun runTransaction(transaction: Transaction): Completable { + val changes = mutableListOf() + return Completable.fromCallable { + database.runInTransaction { + transaction.database = DelegatedAppDatabase(changes, database) + transaction.run() + } + }.subscribeOn(Schedulers.io()).doOnComplete { + changeSubject.onNext(changes) + } + } + + /** + * Executes a transaction and returns its result + * Runs on IO scheduler + */ + fun runTransactionForResult(transaction: Transaction): Single { + val changes = mutableListOf() + return Single.fromCallable { + database.runInTransaction(Callable { + transaction.database = DelegatedAppDatabase(changes, database) + transaction.run() + }) + }.subscribeOn(Schedulers.io()).doOnSuccess { + changeSubject.onNext(changes) + } + } + + fun clearDatabases() = database.clearAllTables() + + //BG READINGS -- only valid records + fun compatGetBgReadingsDataFromTime(timestamp: Long, ascending: Boolean) = + database.glucoseValueDao.compatGetBgReadingsDataFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun compatGetBgReadingsDataFromTime(start: Long, end: Long, ascending: Boolean) = + database.glucoseValueDao.compatGetBgReadingsDataFromTime(start, end) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + //BG READINGS -- including invalid/history records + fun findBgReadingByNSIdSingle(nsId: String): Single> = + database.glucoseValueDao.findByNSIdMaybe(nsId).toWrappedSingle() + + fun getModifiedBgReadingsDataFromId(lastId: Long) = + database.glucoseValueDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + + fun getBgReadingsCorrespondingLastHistoryRecord(lastId: Long) = + database.glucoseValueDao.getLastHistoryRecord(lastId) + + @Suppress("unused") // debug purpose only + fun getAllBgReadingsStartingFrom(lastId: Long) = + database.glucoseValueDao.getAllStartingFrom(lastId) + .subscribeOn(Schedulers.io()) + + // TEMP TARGETS + fun compatGetTemporaryTargetData() = + database.temporaryTargetDao.compatGetTemporaryTargetData() + + fun compatGetTemporaryTargetDataFromTime(timestamp: Long, ascending: Boolean) = + database.temporaryTargetDao.compatGetTemporaryTargetDataFromTime(timestamp) + .map { if (!ascending) it.reversed() else it } + .subscribeOn(Schedulers.io()) + + fun findTemporaryTargetByNSIdSingle(nsId: String): Single> = + database.temporaryTargetDao.findByNSIdMaybe(nsId).toWrappedSingle() + + fun getModifiedTemporaryTargetsDataFromId(lastId: Long) = + database.temporaryTargetDao.getModifiedFrom(lastId) + .subscribeOn(Schedulers.io()) + + fun getTemporaryTargetsCorrespondingLastHistoryRecord(lastId: Long) = + database.temporaryTargetDao.getLastHistoryRecord(lastId) + +} + +inline fun Maybe.toWrappedSingle(): Single> = + this.map { ValueWrapper.Existing(it) as ValueWrapper } + .switchIfEmpty(Maybe.just(ValueWrapper.Absent())) + .toSingle() + +sealed class ValueWrapper { + data class Existing(val value: T) : ValueWrapper() + class Absent : ValueWrapper() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/Converters.kt b/database/src/main/java/info/nightscout/androidaps/database/Converters.kt new file mode 100644 index 0000000000..cdac1563d5 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/Converters.kt @@ -0,0 +1,142 @@ +package info.nightscout.androidaps.database + +import androidx.room.TypeConverter +import info.nightscout.androidaps.database.data.Block +import info.nightscout.androidaps.database.data.TargetBlock +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.* +import org.json.JSONArray +import org.json.JSONObject + +class Converters { + + @TypeConverter + fun fromBolusType(bolusType: Bolus.Type?) = bolusType?.name + + @TypeConverter + fun toBolusType(bolusType: String?) = bolusType?.let { Bolus.Type.valueOf(it) } + + @TypeConverter + fun fromTrendArrow(trendArrow: GlucoseValue.TrendArrow?) = trendArrow?.name + + @TypeConverter + fun toTrendArrow(trendArrow: String?) = trendArrow?.let { GlucoseValue.TrendArrow.valueOf(it) } + + @TypeConverter + fun fromSourceSensor(sourceSensor: GlucoseValue.SourceSensor?) = sourceSensor?.name + + @TypeConverter + fun toSourceSensor(sourceSensor: String?) = sourceSensor?.let { GlucoseValue.SourceSensor.valueOf(it) } + + @TypeConverter + fun fromTBRType(tbrType: TemporaryBasal.Type?) = tbrType?.name + + @TypeConverter + fun toTBRType(tbrType: String?) = tbrType?.let { TemporaryBasal.Type.valueOf(it) } + + @TypeConverter + fun fromTempTargetReason(tempTargetReason: TemporaryTarget.Reason?) = tempTargetReason?.name + + @TypeConverter + fun toTempTargetReason(tempTargetReason: String?) = tempTargetReason?.let { TemporaryTarget.Reason.valueOf(it) } + + @TypeConverter + fun fromTherapyEventType(therapyEventType: TherapyEvent.Type?) = therapyEventType?.name + + @TypeConverter + fun toTherapyEventType(therapyEventType: String?) = therapyEventType?.let { TherapyEvent.Type.valueOf(it) } + + @TypeConverter + fun fromGlucoseUnit(glucoseUnit: ProfileSwitch.GlucoseUnit?) = glucoseUnit?.name + + @TypeConverter + fun toGlucoseUnit(glucoseUnit: String?) = glucoseUnit?.let { ProfileSwitch.GlucoseUnit.valueOf(it) } + + @TypeConverter + fun fromPumpType(pumpType: InterfaceIDs.PumpType?) = pumpType?.name + + @TypeConverter + fun toPumpType(pumpType: String?) = pumpType?.let { InterfaceIDs.PumpType.valueOf(it) } + + @TypeConverter + fun fromAlgorithm(algorithm: APSResult.Algorithm?) = algorithm?.name + + @TypeConverter + fun toAlgorithm(algorithm: String?) = algorithm?.let { APSResult.Algorithm.valueOf(it) } + + @TypeConverter + fun fromListOfBlocks(blocks: List?): String? { + if (blocks == null) return null + val jsonArray = JSONArray() + blocks.forEach { + val jsonObject = JSONObject() + jsonObject.put("duration", it.duration) + jsonObject.put("amount", it.amount) + jsonArray.put(jsonObject) + } + return jsonArray.toString() + } + + @TypeConverter + fun toListOfBlocks(jsonString: String?): List? { + if (jsonString == null) return null + val jsonArray = JSONArray(jsonString) + val list = mutableListOf() + for (i in 0 until jsonArray.length()) { + val jsonObject = jsonArray.getJSONObject(i) + list.add(Block(jsonObject.getLong("duration"), jsonObject.getDouble("amount"))) + } + return list + } + + @TypeConverter + fun anyToString(value: Any?) = when (value) { + null -> null + is String -> "S$value" + is Int -> "I$value" + is Long -> "L$value" + is Boolean -> "B$value" + is Float -> "F$value" + else -> throw IllegalArgumentException("Type not supported") + } + + @TypeConverter + fun stringToAny(value: String?): Any? = when { + value == null -> null + value.startsWith("S") -> value.substring(1) + value.startsWith("I") -> value.substring(1).toInt() + value.startsWith("L") -> value.substring(1).toLong() + value.startsWith("B") -> value.substring(1).toBoolean() + value.startsWith("F") -> value.substring(1).toFloat() + else -> throw IllegalArgumentException("Type not supported") + } + + @TypeConverter + fun fromListOfTargetBlocks(blocks: List?): String? { + if (blocks == null) return null + val jsonArray = JSONArray() + blocks.forEach { + val jsonObject = JSONObject() + jsonObject.put("duration", it.duration) + jsonObject.put("lowTarget", it.lowTarget) + jsonObject.put("highTarget", it.highTarget) + jsonArray.put(jsonObject) + } + return jsonArray.toString() + } + + @TypeConverter + fun toListOfTargetBlocks(jsonString: String?): List? { + if (jsonString == null) return null + val jsonArray = JSONArray(jsonString) + val list = mutableListOf() + for (i in 0 until jsonArray.length()) { + val jsonObject = jsonArray.getJSONObject(i) + list.add(TargetBlock(jsonObject.getLong("duration"), + jsonObject.getDouble("lowTarget"), + jsonObject.getDouble("highTarget"))) + } + return list + } + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt b/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt new file mode 100644 index 0000000000..dda8cf3917 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/DatabaseModule.kt @@ -0,0 +1,24 @@ +package info.nightscout.androidaps.database + +import android.content.Context +import androidx.room.Room +import dagger.Module +import dagger.Provides +import javax.inject.Qualifier +import javax.inject.Singleton + +@Module +open class DatabaseModule { + + @DbFileName + @Provides + fun dbFileName() = "androidaps.db" + + @Provides + @Singleton + internal fun provideAppDatabase(context: Context, @DbFileName fileName: String) = + Room.databaseBuilder(context, AppDatabase::class.java, fileName).build() + + @Qualifier + annotation class DbFileName +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt b/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt new file mode 100644 index 0000000000..1a6e3206b0 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/DelegatedAppDatabase.kt @@ -0,0 +1,27 @@ +package info.nightscout.androidaps.database + +import info.nightscout.androidaps.database.daos.* +import info.nightscout.androidaps.database.daos.delegated.* +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedAppDatabase(val changes: MutableList, val database: AppDatabase) { + + val glucoseValueDao: GlucoseValueDao = DelegatedGlucoseValueDao(changes, database.glucoseValueDao) + val therapyEventDao: TherapyEventDao = DelegatedTherapyEventDao(changes, database.therapyEventDao) + val temporaryBasalDao: TemporaryBasalDao = DelegatedTemporaryBasalDao(changes, database.temporaryBasalDao) + val bolusDao: BolusDao = DelegatedBolusDao(changes, database.bolusDao) + val extendedBolusDao: ExtendedBolusDao = DelegatedExtendedExtendedBolusDao(changes, database.extendedBolusDao) + val multiwaveBolusLinkDao: MultiwaveBolusLinkDao = DelegatedMultiwaveBolusLinkDao(changes, database.multiwaveBolusLinkDao) + val totalDailyDoseDao: TotalDailyDoseDao = DelegatedTotalDailyDoseDao(changes, database.totalDailyDoseDao) + val carbsDao: CarbsDao = DelegatedCarbsDao(changes, database.carbsDao) + val mealLinkDao: MealLinkDao = DelegatedMealLinkDao(changes, database.mealLinkDao) + val temporaryTargetDao: TemporaryTargetDao = DelegatedTemporaryTargetDao(changes, database.temporaryTargetDao) + val apsResultLinkDao: APSResultLinkDao = DelegatedAPSResultLinkLinkDao(changes, database.apsResultLinkDao) + val bolusCalculatorResultDao: BolusCalculatorResultDao = DelegatedBolusCalculatorResultDao(changes, database.bolusCalculatorResultDao) + val effectiveProfileSwitchDao: EffectiveProfileSwitchDao = DelegatedEffectiveProfileSwitchDao(changes, database.effectiveProfileSwitchDao) + val profileSwitchDao: ProfileSwitchDao = DelegatedProfileSwitchDao(changes, database.profileSwitchDao) + val apsResultDao: APSResultDao = DelegatedAPSResultDao(changes, database.apsResultDao) + val versionChangeDao: VersionChangeDao = DelegatedVersionChangeDao(changes, database.versionChangeDao) + val preferenceChangeDao: PreferenceChangeDao = DelegatedPreferenceChangeDao(changes, database.preferenceChangeDao) + fun clearAllTables() = database.clearAllTables() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt b/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt new file mode 100644 index 0000000000..8ecb6beeff --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/TableNames.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.database + +const val TABLE_APS_RESULTS = "apsResults" +const val TABLE_APS_RESULT_LINKS = "apsResultLinks" +const val TABLE_BOLUSES = "boluses" +const val TABLE_BOLUS_CALCULATOR_RESULTS = "bolusCalculatorResults" +const val TABLE_CARBS = "carbs" +const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches" +const val TABLE_EXTENDED_BOLUSES = "extendedBoluses" +const val TABLE_GLUCOSE_VALUES = "glucoseValues" +const val TABLE_MEAL_LINKS = "mealLinks" +const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks" +const val TABLE_PROFILE_SWITCHES = "profileSwitches" +const val TABLE_TEMPORARY_BASALS = "temporaryBasals" +const val TABLE_TEMPORARY_TARGETS = "temporaryTargets" +const val TABLE_TOTAL_DAILY_DOSES = "totalDailyDoses" +const val TABLE_THERAPY_EVENTS = "therapyEvents" +const val TABLE_PREFERENCE_CHANGES = "preferenceChanges" +const val TABLE_VERSION_CHANGES = "versionChanges" \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/APSResultDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/APSResultDao.kt new file mode 100644 index 0000000000..62a1608cdb --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/APSResultDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_APS_RESULTS +import info.nightscout.androidaps.database.entities.APSResult +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface APSResultDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_APS_RESULTS WHERE id = :id") + override fun findById(id: Long): APSResult? + + @Query("DELETE FROM $TABLE_APS_RESULTS") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/APSResultLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/APSResultLinkDao.kt new file mode 100644 index 0000000000..e19a605897 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/APSResultLinkDao.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_APS_RESULTS +import info.nightscout.androidaps.database.TABLE_APS_RESULT_LINKS +import info.nightscout.androidaps.database.entities.APSResultLink +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface APSResultLinkDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_APS_RESULT_LINKS WHERE id = :id") + override fun findById(id: Long): APSResultLink? + + @Query("DELETE FROM $TABLE_APS_RESULTS") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/BolusCalculatorResultDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusCalculatorResultDao.kt new file mode 100644 index 0000000000..a4602a7d73 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusCalculatorResultDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_BOLUS_CALCULATOR_RESULTS +import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface BolusCalculatorResultDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE id = :id") + override fun findById(id: Long): BolusCalculatorResult? + + @Query("DELETE FROM $TABLE_BOLUS_CALCULATOR_RESULTS") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt new file mode 100644 index 0000000000..18e0ae0121 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/BolusDao.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_BOLUSES +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.Bolus +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface BolusDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_BOLUSES WHERE id = :id") + override fun findById(id: Long): Bolus? + + @Query("DELETE FROM $TABLE_BOLUSES") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt new file mode 100644 index 0000000000..09d24908d0 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/CarbsDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_CARBS +import info.nightscout.androidaps.database.entities.Carbs +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface CarbsDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_CARBS WHERE id = :id") + override fun findById(id: Long): Carbs? + + @Query("DELETE FROM $TABLE_CARBS") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/EffectiveProfileSwitchDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/EffectiveProfileSwitchDao.kt new file mode 100644 index 0000000000..8419b30e3e --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/EffectiveProfileSwitchDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_EFFECTIVE_PROFILE_SWITCHES +import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface EffectiveProfileSwitchDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES WHERE id = :id") + override fun findById(id: Long): EffectiveProfileSwitch? + + @Query("DELETE FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/ExtendedBolusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/ExtendedBolusDao.kt new file mode 100644 index 0000000000..c5e0b979bd --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/ExtendedBolusDao.kt @@ -0,0 +1,20 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_EXTENDED_BOLUSES +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.ExtendedBolus +import io.reactivex.Flowable +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface ExtendedBolusDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE id = :id") + override fun findById(id: Long): ExtendedBolus? + + @Query("DELETE FROM $TABLE_EXTENDED_BOLUSES") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt new file mode 100644 index 0000000000..fdaefe78ad --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/GlucoseValueDao.kt @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_GLUCOSE_VALUES +import info.nightscout.androidaps.database.entities.GlucoseValue +import io.reactivex.Maybe +import io.reactivex.Single + +@Dao +internal interface GlucoseValueDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id = :id") + override fun findById(id: Long): GlucoseValue? + + @Query("DELETE FROM $TABLE_GLUCOSE_VALUES") + override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE nightscoutId = :nsId AND referenceId IS NULL") + fun findByNSIdMaybe(nsId: String): Maybe + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE timestamp = :timestamp AND sourceSensor = :sourceSensor AND referenceId IS NULL") + fun findByTimestampAndSensor(timestamp: Long, sourceSensor: GlucoseValue.SourceSensor): GlucoseValue? + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL AND value >= 39 ORDER BY timestamp ASC") + fun compatGetBgReadingsDataFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE timestamp BETWEEN :start AND :end AND isValid = 1 AND referenceId IS NULL AND value >= 39 ORDER BY timestamp ASC") + fun compatGetBgReadingsDataFromTime(start: Long, end: Long): Single> + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id > :lastId AND referenceId IS NULL ORDER BY timestamp ASC") + fun getDataFromId(lastId: Long): Single> + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id >= :id") + fun getAllStartingFrom(id: Long): Single> + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE referenceId = :id ORDER BY id DESC LIMIT 1") + fun getLastHistoryRecord(id: Long): GlucoseValue? + + @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_GLUCOSE_VALUES WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/MealLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/MealLinkDao.kt new file mode 100644 index 0000000000..86c6904e30 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/MealLinkDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_MEAL_LINKS +import info.nightscout.androidaps.database.entities.MealLink +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface MealLinkDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_MEAL_LINKS WHERE id = :id") + override fun findById(id: Long): MealLink? + + @Query("DELETE FROM $TABLE_MEAL_LINKS") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/MultiwaveBolusLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/MultiwaveBolusLinkDao.kt new file mode 100644 index 0000000000..d7865779b7 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/MultiwaveBolusLinkDao.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_MEAL_LINKS +import info.nightscout.androidaps.database.TABLE_MULTIWAVE_BOLUS_LINKS +import info.nightscout.androidaps.database.entities.MultiwaveBolusLink +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface MultiwaveBolusLinkDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_MULTIWAVE_BOLUS_LINKS WHERE id = :id") + override fun findById(id: Long): MultiwaveBolusLink? + + @Query("DELETE FROM $TABLE_MEAL_LINKS") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/PreferenceChangeDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/PreferenceChangeDao.kt new file mode 100644 index 0000000000..49388a6d37 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/PreferenceChangeDao.kt @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_PREFERENCE_CHANGES +import info.nightscout.androidaps.database.entities.PreferenceChange +import io.reactivex.Single + +@Dao +interface PreferenceChangeDao { + + @Insert + fun insert(preferenceChange: PreferenceChange) + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/ProfileSwitchDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/ProfileSwitchDao.kt new file mode 100644 index 0000000000..574a9353d8 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/ProfileSwitchDao.kt @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_PROFILE_SWITCHES +import info.nightscout.androidaps.database.data.checkSanity +import info.nightscout.androidaps.database.daos.workaround.ProfileSwitchDaoWorkaround +import info.nightscout.androidaps.database.entities.ProfileSwitch +import io.reactivex.Flowable +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface ProfileSwitchDao : ProfileSwitchDaoWorkaround { + + @Query("SELECT * FROM $TABLE_PROFILE_SWITCHES WHERE id = :id") + override fun findById(id: Long): ProfileSwitch? + + @Query("DELETE FROM $TABLE_PROFILE_SWITCHES") + override fun deleteAllEntries() +} + +internal fun ProfileSwitchDao.insertNewEntryImpl(entry: ProfileSwitch): Long { + if (!entry.basalBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for basal blocks.") + if (!entry.icBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for IC blocks.") + if (!entry.isfBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for ISF blocks.") + if (!entry.targetBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for target blocks.") + return (this as TraceableDao).insertNewEntryImpl(entry) +} + +internal fun ProfileSwitchDao.updateExistingEntryImpl(entry: ProfileSwitch): Long { + if (!entry.basalBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for basal blocks.") + if (!entry.icBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for IC blocks.") + if (!entry.isfBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for ISF blocks.") + if (!entry.targetBlocks.checkSanity()) throw IllegalArgumentException("Sanity check failed for target blocks.") + return (this as TraceableDao).updateExistingEntryImpl(entry) +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt new file mode 100644 index 0000000000..b2b88a1c7a --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryBasalDao.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_TEMPORARY_BASALS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.TemporaryBasal +import io.reactivex.Flowable +import io.reactivex.Maybe +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface TemporaryBasalDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE id = :id") + override fun findById(id: Long): TemporaryBasal? + + @Query("DELETE FROM $TABLE_TEMPORARY_BASALS") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt new file mode 100644 index 0000000000..bab28cfbc1 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TemporaryTargetDao.kt @@ -0,0 +1,38 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_TEMPORARY_TARGETS +import info.nightscout.androidaps.database.entities.TemporaryTarget +import io.reactivex.Maybe +import io.reactivex.Observable +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface TemporaryTargetDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id = :id") + override fun findById(id: Long): TemporaryTarget? + + @Query("DELETE FROM $TABLE_TEMPORARY_TARGETS") + override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE nightscoutId = :nsId AND referenceId IS NULL") + fun findByNSIdMaybe(nsId: String): Maybe + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp <= :timestamp AND (timestamp + duration) > :timestamp AND referenceId IS NULL AND isValid = 1 ORDER BY timestamp DESC LIMIT 1") + fun getTemporaryTargetActiveAt(timestamp: Long): TemporaryTarget? + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE timestamp >= :timestamp AND isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") + fun compatGetTemporaryTargetDataFromTime(timestamp: Long): Single> + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE isValid = 1 AND referenceId IS NULL ORDER BY timestamp ASC") + fun compatGetTemporaryTargetData(): List + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE referenceId = :id ORDER BY id DESC LIMIT 1") + fun getLastHistoryRecord(id: Long): TemporaryTarget? + + @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id AND referenceId IS NULL OR id IN (SELECT DISTINCT referenceId FROM $TABLE_TEMPORARY_TARGETS WHERE id > :id) ORDER BY id ASC") + fun getModifiedFrom(id: Long): Single> +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TherapyEventDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TherapyEventDao.kt new file mode 100644 index 0000000000..627b896a7c --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TherapyEventDao.kt @@ -0,0 +1,24 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_THERAPY_EVENTS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.entities.TherapyEvent +import io.reactivex.Flowable +import io.reactivex.Maybe +import io.reactivex.Single + +@Dao +internal interface TherapyEventDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE id = :id") + override fun findById(id: Long): TherapyEvent? + + @Query("DELETE FROM $TABLE_THERAPY_EVENTS") + override fun deleteAllEntries() + + @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND timestamp = :timestamp AND referenceId IS NULL") + fun findByTimestamp(type: TherapyEvent.Type, timestamp: Long): TherapyEvent? + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TotalDailyDoseDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TotalDailyDoseDao.kt new file mode 100644 index 0000000000..16ad4e0253 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TotalDailyDoseDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_TOTAL_DAILY_DOSES +import info.nightscout.androidaps.database.entities.TotalDailyDose +import io.reactivex.Single + +@Suppress("FunctionName") +@Dao +internal interface TotalDailyDoseDao : TraceableDao { + + @Query("SELECT * FROM $TABLE_TOTAL_DAILY_DOSES WHERE id = :id") + override fun findById(id: Long): TotalDailyDose? + + @Query("DELETE FROM $TABLE_TOTAL_DAILY_DOSES") + override fun deleteAllEntries() +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/TraceableDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/TraceableDao.kt new file mode 100644 index 0000000000..7eed5e5528 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/TraceableDao.kt @@ -0,0 +1,60 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Insert +import androidx.room.Update +import info.nightscout.androidaps.database.daos.workaround.TraceableDaoWorkaround +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import io.reactivex.Single + +internal interface TraceableDao : TraceableDaoWorkaround { + + fun findById(id: Long): T? + + fun deleteAllEntries() + + //fun getAllStartingFrom(id: Long): Single> + + @Insert + fun insert(entry: T): Long + + @Update + fun update(entry: T) +} + +/** + * Inserts a new entry + * @return The ID of the newly generated entry + */ +//@Transaction +internal fun TraceableDao.insertNewEntryImpl(entry: T): Long { + if (entry.id != 0L) throw IllegalArgumentException("ID must be 0.") + if (entry.version != 0) throw IllegalArgumentException("Version must be 0.") + if (entry.referenceId != null) throw IllegalArgumentException("Reference ID must be null.") + if (!entry.foreignKeysValid) throw IllegalArgumentException("One or more foreign keys are invalid (e.g. 0 value).") + val lastModified = System.currentTimeMillis() + entry.dateCreated = lastModified + val id = insert(entry) + entry.id = id + return id +} + +/** + * Updates an existing entry + * @return The ID of the newly generated HISTORIC entry + */ +//@Transaction +internal fun TraceableDao.updateExistingEntryImpl(entry: T): Long { + if (entry.id == 0L) throw IllegalArgumentException("ID must not be 0.") + if (entry.referenceId != null) throw IllegalArgumentException("Reference ID must be null.") + if (!entry.foreignKeysValid) throw IllegalArgumentException("One or more foreign keys are invalid (e.g. 0 value).") + val lastModified = System.currentTimeMillis() + entry.dateCreated = lastModified + val current = findById(entry.id) + ?: throw IllegalArgumentException("The entry with the specified ID does not exist.") + if (current.referenceId != null) throw IllegalArgumentException("The entry with the specified ID is historic and cannot be updated.") + entry.version = current.version + 1 + update(entry) + current.referenceId = entry.id + current.id = 0 + return insert(current) +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/VersionChangeDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/VersionChangeDao.kt new file mode 100644 index 0000000000..fabbead4fa --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/VersionChangeDao.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.database.daos + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import info.nightscout.androidaps.database.TABLE_VERSION_CHANGES +import info.nightscout.androidaps.database.entities.VersionChange +import io.reactivex.Single + +@Dao +interface VersionChangeDao { + + @Insert + fun insert(versionChange: VersionChange) + + @Query("SELECT * FROM $TABLE_VERSION_CHANGES ORDER BY id DESC LIMIT 1") + fun getMostRecentVersionChange(): VersionChange? + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedAPSResultDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedAPSResultDao.kt new file mode 100644 index 0000000000..ffe6180770 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedAPSResultDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.APSResultDao +import info.nightscout.androidaps.database.entities.APSResult +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedAPSResultDao(changes: MutableList, private val dao: APSResultDao) : DelegatedDao(changes), APSResultDao by dao { + + override fun insertNewEntry(entry: APSResult): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: APSResult): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedAPSResultLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedAPSResultLinkDao.kt new file mode 100644 index 0000000000..2152d3f9f0 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedAPSResultLinkDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.APSResultLinkDao +import info.nightscout.androidaps.database.entities.APSResultLink +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedAPSResultLinkLinkDao(changes: MutableList, private val dao: APSResultLinkDao) : DelegatedDao(changes), APSResultLinkDao by dao { + + override fun insertNewEntry(entry: APSResultLink): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: APSResultLink): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedBolusCalculatorResultDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedBolusCalculatorResultDao.kt new file mode 100644 index 0000000000..40e92dcb04 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedBolusCalculatorResultDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.BolusCalculatorResultDao +import info.nightscout.androidaps.database.entities.BolusCalculatorResult +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedBolusCalculatorResultDao(changes: MutableList, private val dao: BolusCalculatorResultDao) : DelegatedDao(changes), BolusCalculatorResultDao by dao { + + override fun insertNewEntry(entry: BolusCalculatorResult): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: BolusCalculatorResult): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedBolusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedBolusDao.kt new file mode 100644 index 0000000000..67afec9e18 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedBolusDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.BolusDao +import info.nightscout.androidaps.database.entities.Bolus +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedBolusDao(changes: MutableList, private val dao: BolusDao) : DelegatedDao(changes), BolusDao by dao { + + override fun insertNewEntry(entry: Bolus): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: Bolus): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedCarbsDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedCarbsDao.kt new file mode 100644 index 0000000000..0a2da34a05 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedCarbsDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.CarbsDao +import info.nightscout.androidaps.database.entities.Carbs +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedCarbsDao(changes: MutableList, private val dao: CarbsDao) : DelegatedDao(changes), CarbsDao by dao { + + override fun insertNewEntry(entry: Carbs): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: Carbs): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedDao.kt new file mode 100644 index 0000000000..ff5fe9ba64 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedDao.kt @@ -0,0 +1,8 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.interfaces.DBEntry + +/** + * A DAO that adds updated or inserted entries to a list + */ +internal abstract class DelegatedDao(protected val changes: MutableList) \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedEffectiveProfileSwitchDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedEffectiveProfileSwitchDao.kt new file mode 100644 index 0000000000..6516ffbc6c --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedEffectiveProfileSwitchDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.EffectiveProfileSwitchDao +import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedEffectiveProfileSwitchDao(changes: MutableList, private val dao: EffectiveProfileSwitchDao) : DelegatedDao(changes), EffectiveProfileSwitchDao by dao { + + override fun insertNewEntry(entry: EffectiveProfileSwitch): Long { + changes.add(entry) + return super.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: EffectiveProfileSwitch): Long { + changes.add(entry) + return super.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedExtendedBolusDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedExtendedBolusDao.kt new file mode 100644 index 0000000000..fa3a6369fd --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedExtendedBolusDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.ExtendedBolusDao +import info.nightscout.androidaps.database.entities.ExtendedBolus +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedExtendedExtendedBolusDao(changes: MutableList, private val dao: ExtendedBolusDao) : DelegatedDao(changes), ExtendedBolusDao by dao { + + override fun insertNewEntry(entry: ExtendedBolus): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: ExtendedBolus): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedGlucoseValueDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedGlucoseValueDao.kt new file mode 100644 index 0000000000..d16e84ebc5 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedGlucoseValueDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.GlucoseValueDao +import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedGlucoseValueDao(changes: MutableList, private val dao: GlucoseValueDao) : DelegatedDao(changes), GlucoseValueDao by dao { + + override fun insertNewEntry(entry: GlucoseValue): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: GlucoseValue): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMealLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMealLinkDao.kt new file mode 100644 index 0000000000..a568dd5aed --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMealLinkDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.MealLinkDao +import info.nightscout.androidaps.database.entities.MealLink +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedMealLinkDao(changes: MutableList, private val dao: MealLinkDao) : DelegatedDao(changes), MealLinkDao by dao { + + override fun insertNewEntry(entry: MealLink): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: MealLink): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMultiwaveBolusLinkDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMultiwaveBolusLinkDao.kt new file mode 100644 index 0000000000..fd6079a146 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedMultiwaveBolusLinkDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.MultiwaveBolusLinkDao +import info.nightscout.androidaps.database.entities.MultiwaveBolusLink +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedMultiwaveBolusLinkDao(changes: MutableList, private val dao: MultiwaveBolusLinkDao) : DelegatedDao(changes), MultiwaveBolusLinkDao by dao { + + override fun insertNewEntry(entry: MultiwaveBolusLink): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: MultiwaveBolusLink): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedPreferenceChangeDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedPreferenceChangeDao.kt new file mode 100644 index 0000000000..97ba761423 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedPreferenceChangeDao.kt @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.PreferenceChangeDao +import info.nightscout.androidaps.database.entities.PreferenceChange +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedPreferenceChangeDao(changes: MutableList, private val dao: PreferenceChangeDao) : DelegatedDao(changes), PreferenceChangeDao by dao { + + override fun insert(preferenceChange: PreferenceChange) { + changes.add(preferenceChange) + return dao.insert(preferenceChange) + } + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedProfileSwitchDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedProfileSwitchDao.kt new file mode 100644 index 0000000000..11ded9ccdc --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedProfileSwitchDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.ProfileSwitchDao +import info.nightscout.androidaps.database.entities.ProfileSwitch +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedProfileSwitchDao(changes: MutableList, private val dao: ProfileSwitchDao) : DelegatedDao(changes), ProfileSwitchDao by dao { + + override fun insertNewEntry(entry: ProfileSwitch): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: ProfileSwitch): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTemporaryBasalDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTemporaryBasalDao.kt new file mode 100644 index 0000000000..c48ca004cb --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTemporaryBasalDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.TemporaryBasalDao +import info.nightscout.androidaps.database.entities.TemporaryBasal +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedTemporaryBasalDao(changes: MutableList, private val dao: TemporaryBasalDao) : DelegatedDao(changes), TemporaryBasalDao by dao { + + override fun insertNewEntry(entry: TemporaryBasal): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: TemporaryBasal): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTemporaryTargetDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTemporaryTargetDao.kt new file mode 100644 index 0000000000..a3cba800f5 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTemporaryTargetDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.TemporaryTargetDao +import info.nightscout.androidaps.database.entities.TemporaryTarget +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedTemporaryTargetDao(changes: MutableList, private val dao: TemporaryTargetDao) : DelegatedDao(changes), TemporaryTargetDao by dao { + + override fun insertNewEntry(entry: TemporaryTarget): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: TemporaryTarget): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTherapyEventDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTherapyEventDao.kt new file mode 100644 index 0000000000..767edd50a9 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTherapyEventDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.TherapyEventDao +import info.nightscout.androidaps.database.entities.TherapyEvent +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedTherapyEventDao(changes: MutableList, private val dao: TherapyEventDao) : DelegatedDao(changes), TherapyEventDao by dao { + + override fun insertNewEntry(entry: TherapyEvent): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: TherapyEvent): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTotalDailyDoseDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTotalDailyDoseDao.kt new file mode 100644 index 0000000000..95bc5ab108 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedTotalDailyDoseDao.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.TotalDailyDoseDao +import info.nightscout.androidaps.database.entities.TotalDailyDose +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedTotalDailyDoseDao(changes: MutableList, private val dao: TotalDailyDoseDao) : DelegatedDao(changes), TotalDailyDoseDao by dao { + + override fun insertNewEntry(entry: TotalDailyDose): Long { + changes.add(entry) + return dao.insertNewEntry(entry) + } + + override fun updateExistingEntry(entry: TotalDailyDose): Long { + changes.add(entry) + return dao.updateExistingEntry(entry) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedVersionChangeDao.kt b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedVersionChangeDao.kt new file mode 100644 index 0000000000..81a5ecb799 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/delegated/DelegatedVersionChangeDao.kt @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.database.daos.delegated + +import info.nightscout.androidaps.database.daos.VersionChangeDao +import info.nightscout.androidaps.database.entities.VersionChange +import info.nightscout.androidaps.database.interfaces.DBEntry + +internal class DelegatedVersionChangeDao(changes: MutableList, private val dao: VersionChangeDao) : DelegatedDao(changes), VersionChangeDao by dao { + + override fun insert(versionChange: VersionChange) { + changes.add(versionChange) + return dao.insert(versionChange) + } + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/ProfileSwitchDaoWorkaround.java b/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/ProfileSwitchDaoWorkaround.java new file mode 100644 index 0000000000..9a817ff215 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/ProfileSwitchDaoWorkaround.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.database.daos.workaround; + +import androidx.room.Transaction; + +import info.nightscout.androidaps.database.daos.ProfileSwitchDao; +import info.nightscout.androidaps.database.daos.ProfileSwitchDaoKt; +import info.nightscout.androidaps.database.daos.TraceableDao; +import info.nightscout.androidaps.database.entities.ProfileSwitch; + +public interface ProfileSwitchDaoWorkaround extends TraceableDao { + + @Override + @Transaction + default long insertNewEntry(ProfileSwitch entry) { + return ProfileSwitchDaoKt.insertNewEntryImpl((ProfileSwitchDao) this, entry); + } + + @Override + @Transaction + default long updateExistingEntry(ProfileSwitch entry) { + return ProfileSwitchDaoKt.updateExistingEntryImpl((ProfileSwitchDao) this, entry); + } +} diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/TraceableDaoWorkaround.java b/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/TraceableDaoWorkaround.java new file mode 100644 index 0000000000..ddeb1d0d80 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/TraceableDaoWorkaround.java @@ -0,0 +1,31 @@ +package info.nightscout.androidaps.database.daos.workaround; + +import androidx.room.Transaction; + +import info.nightscout.androidaps.database.daos.TraceableDao; +import info.nightscout.androidaps.database.daos.TraceableDaoKt; +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry; + +public interface TraceableDaoWorkaround { + + /** + * Inserts a new entry + * + * @return The ID of the newly generated entry + */ + @Transaction + default long insertNewEntry(T entry) { + return TraceableDaoKt.insertNewEntryImpl((TraceableDao) this, entry); + } + + /** + * Updates an existing entry + * + * @return The ID of the newly generated HISTORIC entry + */ + @Transaction + default long updateExistingEntry(T entry) { + return TraceableDaoKt.updateExistingEntryImpl((TraceableDao) this, entry); + } + +} diff --git a/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/package-info.java b/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/package-info.java new file mode 100644 index 0000000000..089581be3b --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/daos/workaround/package-info.java @@ -0,0 +1,5 @@ +/** + * Workarounds until Kotlin is able to properly translate interface default methods while annotation processing. + * See https://youtrack.jetbrains.com/issue/KT-25960 + */ +package info.nightscout.androidaps.database.daos.workaround; \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/data/Block.kt b/database/src/main/java/info/nightscout/androidaps/database/data/Block.kt new file mode 100644 index 0000000000..0b4a98b5c1 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/data/Block.kt @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.database.data + +import java.util.concurrent.TimeUnit + +data class Block(var duration: Long, var amount: Double) + +fun List.checkSanity(): Boolean { + var sum = 0L + forEach { sum += it.duration } + return sum == TimeUnit.DAYS.toMillis(1) +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/data/TargetBlock.kt b/database/src/main/java/info/nightscout/androidaps/database/data/TargetBlock.kt new file mode 100644 index 0000000000..4c95fba75f --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/data/TargetBlock.kt @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.database.data + +import java.util.concurrent.TimeUnit + +data class TargetBlock(var duration: Long, var lowTarget: Double, var highTarget: Double) + +fun List.checkSanity(): Boolean { + var sum = 0L + forEach { sum += it.duration } + return sum == TimeUnit.DAYS.toMillis(1) +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/embedments/InsulinConfiguration.kt b/database/src/main/java/info/nightscout/androidaps/database/embedments/InsulinConfiguration.kt new file mode 100644 index 0000000000..50450ae52d --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/embedments/InsulinConfiguration.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.database.embedments + +data class InsulinConfiguration( + var insulinLabel: String, + var insulinEndTime: Long, + var peak: Long +) \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt b/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt new file mode 100644 index 0000000000..86873d9915 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/embedments/InterfaceIDs.kt @@ -0,0 +1,20 @@ +package info.nightscout.androidaps.database.embedments + +data class InterfaceIDs( + var nightscoutSystemId: String? = null, + var nightscoutId: String? = null, + var pumpType: PumpType? = null, + var pumpSerial: String? = null, + var pumpId: Long? = null, + var startId: Long? = null, + var endId: Long? = null +) { + enum class PumpType { + ACCU_CHEK_INSIGHT, + ACCU_CHEK_COMBO, + DANA_R, + DANA_RS, + MEDTRONIC, + OMNIPOD + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/APSResult.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/APSResult.kt new file mode 100644 index 0000000000..42ef8e7dac --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/APSResult.kt @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_APS_RESULTS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_APS_RESULTS, + foreignKeys = [ForeignKey( + entity = APSResult::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class APSResult( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var algorithm: Algorithm, + var glucoseStatusJson: String, + var currentTempJson: String, + var iobDataJson: String, + var profileJson: String, + var autosensDataJson: String?, + var mealDataJson: String, + var isMicroBolusAllowed: Boolean?, + var resultJson: String +) : TraceableDBEntry, DBEntryWithTime { + enum class Algorithm { + MA, + AMA, + SMB + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/APSResultLink.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/APSResultLink.kt new file mode 100644 index 0000000000..8fed1f9578 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/APSResultLink.kt @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_APS_RESULT_LINKS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry + +@Entity(tableName = TABLE_APS_RESULT_LINKS, + foreignKeys = [ForeignKey( + entity = APSResult::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("apsResultId")), ForeignKey( + + entity = Bolus::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("smbId")), ForeignKey( + + entity = TemporaryBasal::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("tbrId")), ForeignKey( + + entity = APSResultLink::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("referenceId"))], + indices = [Index("referenceId"), Index("apsResultId"), + Index("smbId"), Index("tbrId")]) +data class APSResultLink( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + var apsResultId: Long, + var smbId: Long? = null, + var tbrId: Long? = null +) : TraceableDBEntry { + override val foreignKeysValid: Boolean + get() = super.foreignKeysValid && apsResultId != 0L && smbId != 0L && tbrId != 0L +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/Bolus.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/Bolus.kt new file mode 100644 index 0000000000..a683ca31f3 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/Bolus.kt @@ -0,0 +1,39 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_BOLUSES +import info.nightscout.androidaps.database.embedments.InsulinConfiguration +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_BOLUSES, + foreignKeys = [ForeignKey( + entity = Bolus::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class Bolus( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var amount: Double, + var type: Type, + var isBasalInsulin: Boolean, + @Embedded + var insulinConfiguration: InsulinConfiguration? = null +) : TraceableDBEntry, DBEntryWithTime { + enum class Type { + NORMAL, + SMB, + PRIMING + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/BolusCalculatorResult.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/BolusCalculatorResult.kt new file mode 100644 index 0000000000..056d1fd363 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/BolusCalculatorResult.kt @@ -0,0 +1,53 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_BOLUS_CALCULATOR_RESULTS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_BOLUS_CALCULATOR_RESULTS, + foreignKeys = [ForeignKey( + entity = BolusCalculatorResult::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class BolusCalculatorResult( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var targetBGLow: Double, + var targetBGHigh: Double, + var isf: Double, + var ic: Double, + var bolusIOB: Double, + var wasBolusIOBUsed: Boolean, + var basalIOB: Double, + var wasBasalIOBUsed: Boolean, + var glucoseValue: Double, + var wasGlucoseUsed: Boolean, + var glucoseDifference: Double, + var glucoseInsulin: Double, + var glucoseTrend: Double, + var wasTrendUsed: Boolean, + var trendInsulin: Double, + var cob: Double, + var wasCOBUsed: Boolean, + var cobInsulin: Double, + var carbs: Double, + var wereCarbsUsed: Boolean, + var carbsInsulin: Double, + var otherCorrection: Double, + var wasSuperbolusUsed: Boolean, + var superbolusInsulin: Double, + var wasTempTargetUsed: Boolean, + var totalInsulin: Double +) : TraceableDBEntry, DBEntryWithTime \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/Carbs.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/Carbs.kt new file mode 100644 index 0000000000..5694d1041a --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/Carbs.kt @@ -0,0 +1,29 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_CARBS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_CARBS, + foreignKeys = [ForeignKey( + entity = Carbs::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class Carbs( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + override var duration: Long, + var amount: Double +) : TraceableDBEntry, DBEntryWithTimeAndDuration \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/EffectiveProfileSwitch.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/EffectiveProfileSwitch.kt new file mode 100644 index 0000000000..273634e25a --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/EffectiveProfileSwitch.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.data.Block +import info.nightscout.androidaps.database.TABLE_EFFECTIVE_PROFILE_SWITCHES +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_EFFECTIVE_PROFILE_SWITCHES, + foreignKeys = [ForeignKey( + entity = EffectiveProfileSwitch::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class EffectiveProfileSwitch( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + override var duration: Long, + var basalBlocks: List +) : TraceableDBEntry, DBEntryWithTimeAndDuration \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/ExtendedBolus.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/ExtendedBolus.kt new file mode 100644 index 0000000000..40792c11c7 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/ExtendedBolus.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_EXTENDED_BOLUSES +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_EXTENDED_BOLUSES, + foreignKeys = [ForeignKey( + entity = ExtendedBolus::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class ExtendedBolus( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + override var duration: Long, + var amount: Double, + var isEmulatingTempBasal: Boolean +) : TraceableDBEntry, DBEntryWithTimeAndDuration \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/GlucoseValue.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/GlucoseValue.kt new file mode 100644 index 0000000000..55716ba4ac --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/GlucoseValue.kt @@ -0,0 +1,100 @@ +package info.nightscout.androidaps.database.entities + +import com.google.gson.annotations.SerializedName +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_GLUCOSE_VALUES +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_GLUCOSE_VALUES, + foreignKeys = [ForeignKey( + entity = GlucoseValue::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class GlucoseValue( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var raw: Double?, + var value: Double, + var trendArrow: TrendArrow, + var noise: Double?, + var sourceSensor: SourceSensor +) : TraceableDBEntry, DBEntryWithTime { + + fun contentEqualsTo(other: GlucoseValue): Boolean = + timestamp == other.timestamp && + utcOffset == other.utcOffset && + raw == other.raw && + value == other.value && + trendArrow == other.trendArrow && + noise == other.noise && + sourceSensor == other.sourceSensor && + isValid == other.isValid + + fun isRecordDeleted(other: GlucoseValue): Boolean = + isValid && !other.isValid + + enum class TrendArrow (val text:String, val symbol:String){ + @SerializedName("NONE") NONE("NONE", "??"), + @SerializedName("TripleUp")TRIPLE_UP("TripleUp", "X"), + @SerializedName("DoubleUp")DOUBLE_UP("DoubleUp", "\u21c8"), + @SerializedName("SingleUp")SINGLE_UP("SingleUp", "\u2191"), + @SerializedName("FortyFiveUp")FORTY_FIVE_UP("FortyFiveUp", "\u2197"), + @SerializedName("Flat")FLAT("Flat", "\u2192"), + @SerializedName("FortyFiveDown")FORTY_FIVE_DOWN("FortyFiveDown", "\u2198"), + @SerializedName("SingleDown")SINGLE_DOWN("SingleDown", "\u2193"), + @SerializedName("DoubleDown")DOUBLE_DOWN("DoubleDown", "\u21ca"), + @SerializedName("TripleDown")TRIPLE_DOWN("TripleDown", "X") + ; + + companion object { + fun fromString(direction : String?) = values().firstOrNull {it.text == direction} ?: NONE + } + } + + enum class SourceSensor(val text : String) { + @SerializedName("AndroidAPS-Dexcom") DEXCOM_NATIVE_UNKNOWN("AndroidAPS-Dexcom"), + @SerializedName("AndroidAPS-DexcomG6") DEXCOM_G6_NATIVE("AndroidAPS-DexcomG6"), + @SerializedName("AndroidAPS-DexcomG5") DEXCOM_G5_NATIVE("AndroidAPS-DexcomG5"), + @SerializedName("Bluetooth Wixel") DEXCOM_G4_WIXEL("Bluetooth Wixel"), + @SerializedName("xBridge Wixel") DEXCOM_G4_XBRIDGE("xBridge Wixel"), + @SerializedName("G4 Share Receiver") DEXCOM_G4_NATIVE("G4 Share Receiver"), + @SerializedName("Medtrum A6") MEDTRUM_A6("Medtrum A6"), + @SerializedName("Network G4") DEXCOM_G4_NET("Network G4"), + @SerializedName("Network G4 and xBridge") DEXCOM_G4_NET_XBRIDGE("Network G4 and xBridge"), + @SerializedName("Network G4 and Classic xDrip") DEXCOM_G4_NET_CLASSIC("Network G4 and Classic xDrip"), + @SerializedName("DexcomG5") DEXCOM_G5_XDRIP("DexcomG5"), + @SerializedName("G6 Native") DEXCOM_G6_NATIVE_XDRIP("G6 Native"), + @SerializedName("G5 Native") DEXCOM_G5_NATIVE_XDRIP("G5 Native"), + @SerializedName("Network libre") LIBRE_1_NET("Network libre"), + @SerializedName("BlueReader") LIBRE_1_BLUE("BlueReader"), + @SerializedName("Transmiter PL") LIBRE_1_PL("Transmiter PL"), + @SerializedName("Blucon") LIBRE_1_BLUCON("Blucon"), + @SerializedName("Tomato") LIBRE_1_TOMATO("Tomato"), + @SerializedName("Rfduino") LIBRE_1_RF("Rfduino"), + @SerializedName("LimiTTer") LIBRE_1_LIMITTER("LimiTTer"), + @SerializedName("Glimp") GLIMP("Glimp"), + @SerializedName("Libre2") LIBRE_2_NATIVE("Libre2"), + @SerializedName("Poctech") POCTECH_NATIVE("Poctech"), + @SerializedName("MM600Series") MM_600_SERIES("MM600Series"), + @SerializedName("Eversense") EVERSENSE("Eversense"), + @SerializedName("Random") RANDOM("Random"), + @SerializedName("Unknown") UNKNOWN("Unknown") + ; + + companion object { + fun fromString(source : String?) = values().firstOrNull {it.text == source} ?: UNKNOWN + } + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/MealLink.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/MealLink.kt new file mode 100644 index 0000000000..4c6a3c5f32 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/MealLink.kt @@ -0,0 +1,54 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_MEAL_LINKS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry + +@Entity(tableName = TABLE_MEAL_LINKS, + foreignKeys = [ForeignKey( + entity = Bolus::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("bolusId")), ForeignKey( + + entity = Carbs::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("carbsId")), ForeignKey( + + entity = BolusCalculatorResult::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("bolusCalcResultId")), ForeignKey( + + entity = TemporaryBasal::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("superbolusTempBasalId")), ForeignKey( + + entity = TherapyEvent::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("noteId")), ForeignKey( + + entity = MealLink::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("bolusId"), + Index("carbsId"), Index("bolusCalcResultId"), + Index("superbolusTempBasalId"), Index("noteId")]) +data class MealLink( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + var bolusId: Long? = null, + var carbsId: Long? = null, + var bolusCalcResultId: Long? = null, + var superbolusTempBasalId: Long? = null, + var noteId: Long? = null +) : TraceableDBEntry { + override val foreignKeysValid: Boolean + get() = super.foreignKeysValid && bolusId != 0L && carbsId != 0L && + bolusCalcResultId != 0L && superbolusTempBasalId != 0L && noteId != 0L +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/MultiwaveBolusLink.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/MultiwaveBolusLink.kt new file mode 100644 index 0000000000..e8fbf135e0 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/MultiwaveBolusLink.kt @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_MULTIWAVE_BOLUS_LINKS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry + +@Entity(tableName = TABLE_MULTIWAVE_BOLUS_LINKS, + foreignKeys = [ForeignKey( + entity = Bolus::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("bolusId")), ForeignKey( + + entity = ExtendedBolus::class, + parentColumns = arrayOf("id"), + childColumns = arrayOf("extendedBolusId")), ForeignKey( + + entity = MultiwaveBolusLink::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("bolusId"), + Index("extendedBolusId")]) +data class MultiwaveBolusLink( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = null, + var bolusId: Long, + var extendedBolusId: Long +) : TraceableDBEntry { + override val foreignKeysValid: Boolean + get() = super.foreignKeysValid && bolusId != 0L && bolusId != 0L && extendedBolusId != 0L +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/PreferenceChange.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/PreferenceChange.kt new file mode 100644 index 0000000000..8ff67ccb71 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/PreferenceChange.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey +import info.nightscout.androidaps.database.TABLE_PREFERENCE_CHANGES +import info.nightscout.androidaps.database.interfaces.DBEntry +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import java.util.TimeZone + +@Entity(tableName = TABLE_PREFERENCE_CHANGES) +data class PreferenceChange( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0L, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var key: String, + var value: Any? +) : DBEntry, DBEntryWithTime \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/ProfileSwitch.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/ProfileSwitch.kt new file mode 100644 index 0000000000..aa845fb8db --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/ProfileSwitch.kt @@ -0,0 +1,46 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.data.Block +import info.nightscout.androidaps.database.TABLE_PROFILE_SWITCHES +import info.nightscout.androidaps.database.data.TargetBlock +import info.nightscout.androidaps.database.embedments.InsulinConfiguration +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_PROFILE_SWITCHES, + foreignKeys = [ForeignKey( + entity = ProfileSwitch::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class ProfileSwitch( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var profileName: String, + var glucoseUnit: GlucoseUnit, + var basalBlocks: List, + var isfBlocks: List, + var icBlocks: List, + var targetBlocks: List, + @Embedded + var insulinConfiguration: InsulinConfiguration, + var timeshift: Int, + var percentage: Int, + override var duration: Long +) : TraceableDBEntry, DBEntryWithTimeAndDuration { + enum class GlucoseUnit { + MGDL, + MMOL + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryBasal.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryBasal.kt new file mode 100644 index 0000000000..01f034ae86 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryBasal.kt @@ -0,0 +1,38 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_TEMPORARY_BASALS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_TEMPORARY_BASALS, + foreignKeys = [ForeignKey( + entity = TemporaryBasal::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class TemporaryBasal( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var type: Type, + var isAbsolute: Boolean, + var rate: Double, + override var duration: Long +) : TraceableDBEntry, DBEntryWithTimeAndDuration { + enum class Type { + NORMAL, + EMULATED_PUMP_SUSPEND, + PUMP_SUSPEND, + SUPERBOLUS + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryTarget.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryTarget.kt new file mode 100644 index 0000000000..96bde2e864 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/TemporaryTarget.kt @@ -0,0 +1,68 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey +import com.google.gson.annotations.SerializedName +import info.nightscout.androidaps.database.TABLE_TEMPORARY_TARGETS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.* + +@Entity(tableName = TABLE_TEMPORARY_TARGETS, + foreignKeys = [ForeignKey( + entity = TemporaryTarget::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class TemporaryTarget( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var reason: Reason, + var highTarget: Double, // in mgdl + var lowTarget: Double, // in mgdl + override var duration: Long // in millis +) : TraceableDBEntry, DBEntryWithTimeAndDuration { + + fun contentEqualsTo(other: TemporaryTarget): Boolean = + timestamp == other.timestamp && + utcOffset == other.utcOffset && + reason == other.reason && + highTarget == other.highTarget && + lowTarget == other.lowTarget && + duration == other.duration && + isValid == other.isValid + + fun isRecordDeleted(other: TemporaryTarget): Boolean = + isValid && !other.isValid + + enum class Reason(val text: String) { + @SerializedName("Custom") + CUSTOM("Custom"), + @SerializedName("Hypo") + HYPOGLYCEMIA("Hypo"), + @SerializedName("Activity") + ACTIVITY("Activity"), + @SerializedName("Eating Soon") + EATING_SOON("Eating Soon"), + @SerializedName("Automation") + AUTOMATION("Automation") + ; + + companion object { + fun fromString(direction: String?) = values().firstOrNull { it.text == direction } + ?: CUSTOM + } + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/TherapyEvent.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/TherapyEvent.kt new file mode 100644 index 0000000000..2225fed98f --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/TherapyEvent.kt @@ -0,0 +1,63 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_THERAPY_EVENTS +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTimeAndDuration +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_THERAPY_EVENTS, + foreignKeys = [ForeignKey( + entity = TherapyEvent::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class TherapyEvent( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + override var duration: Long = 0, + var type: Type, + var note: String? = null, + var amount: Double? = null +) : TraceableDBEntry, DBEntryWithTimeAndDuration { + enum class Type { + CANNULA_CHANGED, + TUBE_CHANGED, + RESERVOIR_CHANGED, + BATTERY_CHANGED, + LEAKING_INFUSION_SET, + SENSOR_INSERTED, + SENSOR_STARTED, + SENSOR_STOPPED, + FINGER_STICK_BG_VALUE, + ACTIVITY, + FALLING_ASLEEP, + WAKING_UP, + SICKNESS, + STRESS, + PRE_PERIOD, + ALCOHOL, + CORTISON, + FEELING_LOW, + FEELING_HIGH, + ANNOUNCEMENT, + QUESTION, + NOTE, + APS_OFFLINE, + BATTERY_EMPTY, + RESERVOIR_EMPTY, + OCCLUSION, + PUMP_STOPPED, + PUMP_STARTED, + PUMP_PAUSED + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/TotalDailyDose.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/TotalDailyDose.kt new file mode 100644 index 0000000000..0cd450697c --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/TotalDailyDose.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.* +import info.nightscout.androidaps.database.TABLE_TOTAL_DAILY_DOSES +import info.nightscout.androidaps.database.embedments.InterfaceIDs +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import info.nightscout.androidaps.database.interfaces.TraceableDBEntry +import java.util.TimeZone + +@Entity(tableName = TABLE_TOTAL_DAILY_DOSES, + foreignKeys = [ForeignKey( + entity = TotalDailyDose::class, + parentColumns = ["id"], + childColumns = ["referenceId"])], + indices = [Index("referenceId"), Index("timestamp")]) +data class TotalDailyDose( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0, + override var version: Int = 0, + override var dateCreated: Long = -1, + override var isValid: Boolean = true, + override var referenceId: Long? = null, + @Embedded + override var interfaceIDs_backing: InterfaceIDs? = InterfaceIDs(), + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var basalAmount: Double?, + var bolusAmount: Double?, + var totalAmount: Double? +) : TraceableDBEntry, DBEntryWithTime \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/entities/VersionChange.kt b/database/src/main/java/info/nightscout/androidaps/database/entities/VersionChange.kt new file mode 100644 index 0000000000..83ca1ccc40 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/entities/VersionChange.kt @@ -0,0 +1,20 @@ +package info.nightscout.androidaps.database.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey +import info.nightscout.androidaps.database.TABLE_VERSION_CHANGES +import info.nightscout.androidaps.database.interfaces.DBEntry +import info.nightscout.androidaps.database.interfaces.DBEntryWithTime +import java.util.TimeZone + +@Entity(tableName = TABLE_VERSION_CHANGES) +data class VersionChange( + @PrimaryKey(autoGenerate = true) + override var id: Long = 0L, + override var timestamp: Long, + override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(), + var versionCode: Int, + var versionName: String, + var gitRemote: String?, + var commitHash: String? +) : DBEntry, DBEntryWithTime \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntry.kt b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntry.kt new file mode 100644 index 0000000000..f6c01287a6 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntry.kt @@ -0,0 +1,5 @@ +package info.nightscout.androidaps.database.interfaces + +interface DBEntry { + var id: Long +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithDuration.kt b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithDuration.kt new file mode 100644 index 0000000000..469ec17d6d --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithDuration.kt @@ -0,0 +1,7 @@ +package info.nightscout.androidaps.database.interfaces + +interface DBEntryWithDuration { + var duration: Long + + val durationUnknown get() = duration == Long.MAX_VALUE +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithTime.kt b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithTime.kt new file mode 100644 index 0000000000..103942fcf0 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithTime.kt @@ -0,0 +1,6 @@ +package info.nightscout.androidaps.database.interfaces + +interface DBEntryWithTime { + var timestamp: Long + var utcOffset: Long +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithTimeAndDuration.kt b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithTimeAndDuration.kt new file mode 100644 index 0000000000..b4f3f0bbbf --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/interfaces/DBEntryWithTimeAndDuration.kt @@ -0,0 +1,14 @@ +package info.nightscout.androidaps.database.interfaces + +import kotlin.math.min + +interface DBEntryWithTimeAndDuration : DBEntryWithTime, DBEntryWithDuration + +var DBEntryWithTimeAndDuration.end + get() = timestamp + duration + set(value) { + duration = value - timestamp + } + +@JvmOverloads +fun DBEntryWithTimeAndDuration.getRemainingDuration(current: Long = System.currentTimeMillis()) = min(0L, end - current) \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/interfaces/TraceableDBEntry.kt b/database/src/main/java/info/nightscout/androidaps/database/interfaces/TraceableDBEntry.kt new file mode 100644 index 0000000000..7ab0ce0984 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/interfaces/TraceableDBEntry.kt @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.database.interfaces + +import info.nightscout.androidaps.database.embedments.InterfaceIDs + +interface TraceableDBEntry: DBEntry { + var version: Int + var dateCreated: Long + var isValid: Boolean + var referenceId: Long? + var interfaceIDs_backing: InterfaceIDs? + + val historic: Boolean get() = referenceId != null + + val foreignKeysValid: Boolean get() = referenceId != 0L + + var interfaceIDs: InterfaceIDs + get() { + var value = this.interfaceIDs_backing + if (value == null) { + value = InterfaceIDs() + interfaceIDs_backing = value + } + return value + } + set(value) { + interfaceIDs_backing = value + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/CancelCurrentTemporaryTargetIfAnyTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/CancelCurrentTemporaryTargetIfAnyTransaction.kt new file mode 100644 index 0000000000..206e9c1d1c --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/CancelCurrentTemporaryTargetIfAnyTransaction.kt @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryTarget +import info.nightscout.androidaps.database.interfaces.end + +class CancelCurrentTemporaryTargetIfAnyTransaction( + val timestamp: Long +) : Transaction() { + override fun run() { + val current = database.temporaryTargetDao.getTemporaryTargetActiveAt(timestamp) + if (current != null) { + current.end = timestamp + database.temporaryTargetDao.updateExistingEntry(current) + } + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/CgmSourceTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/CgmSourceTransaction.kt new file mode 100644 index 0000000000..7a9a5a2dda --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/CgmSourceTransaction.kt @@ -0,0 +1,74 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.GlucoseValue +import info.nightscout.androidaps.database.entities.TherapyEvent + +/** + * Inserts data from a CGM source into the database + */ +class CgmSourceTransaction( + private val glucoseValues: List, + private val calibrations: List, + private val sensorInsertionTime: Long? +) : Transaction>() { + + override fun run(): List { + val insertedGlucoseValues = mutableListOf() + glucoseValues.forEach { + val current = database.glucoseValueDao.findByTimestampAndSensor(it.timestamp, it.sourceSensor) + val glucoseValue = GlucoseValue( + timestamp = it.timestamp, + raw = it.raw, + value = it.value, + noise = it.noise, + trendArrow = it.trendArrow, + sourceSensor = it.sourceSensor + ) + glucoseValue.interfaceIDs.nightscoutId = it.nightscoutId + when { + current == null -> { + database.glucoseValueDao.insertNewEntry(glucoseValue) + insertedGlucoseValues.add(glucoseValue) + } + + !current.contentEqualsTo(glucoseValue) -> { + glucoseValue.id = current.id + database.glucoseValueDao.updateExistingEntry(glucoseValue) + } + } + } + calibrations.forEach { + if (database.therapyEventDao.findByTimestamp(TherapyEvent.Type.FINGER_STICK_BG_VALUE, it.timestamp) == null) { + database.therapyEventDao.insertNewEntry(TherapyEvent( + timestamp = it.timestamp, + type = TherapyEvent.Type.FINGER_STICK_BG_VALUE, + amount = it.value + )) + } + } + sensorInsertionTime?.let { + if (database.therapyEventDao.findByTimestamp(TherapyEvent.Type.SENSOR_INSERTED, it) == null) { + database.therapyEventDao.insertNewEntry(TherapyEvent( + timestamp = it, + type = TherapyEvent.Type.SENSOR_INSERTED + )) + } + } + return insertedGlucoseValues + } + + data class TransactionGlucoseValue( + val timestamp: Long, + val value: Double, + val raw: Double?, + val noise: Double?, + val trendArrow: GlucoseValue.TrendArrow, + val nightscoutId: String? = null, + val sourceSensor: GlucoseValue.SourceSensor + ) + + data class Calibration( + val timestamp: Long, + val value: Double + ) +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertGlucoseValueTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertGlucoseValueTransaction.kt new file mode 100644 index 0000000000..b75c4a3928 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertGlucoseValueTransaction.kt @@ -0,0 +1,13 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.GlucoseValue + +/** + * Creates the GlucoseValue + */ +class InsertGlucoseValueTransaction(val glucoseValue: GlucoseValue) : Transaction() { + + override fun run() { + database.glucoseValueDao.insert(glucoseValue) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryTargetAndCancelCurrentTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryTargetAndCancelCurrentTransaction.kt new file mode 100644 index 0000000000..c3d42b3e52 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InsertTemporaryTargetAndCancelCurrentTransaction.kt @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryTarget +import info.nightscout.androidaps.database.interfaces.end + +class InsertTemporaryTargetAndCancelCurrentTransaction( + private val temporaryTarget: TemporaryTarget +) : Transaction() { + + constructor(timestamp: Long, duration: Long, reason: TemporaryTarget.Reason, lowTarget: Double, highTarget: Double) : + this(TemporaryTarget(timestamp = timestamp, reason = reason, lowTarget = lowTarget, highTarget = highTarget, duration = duration)) + + override fun run() { + val current = database.temporaryTargetDao.getTemporaryTargetActiveAt(temporaryTarget.timestamp) + if (current != null) { + current.end = temporaryTarget.timestamp + database.temporaryTargetDao.updateExistingEntry(current) + } + database.temporaryTargetDao.insertNewEntry(temporaryTarget) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateGlucoseValueTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateGlucoseValueTransaction.kt new file mode 100644 index 0000000000..69895ed8bd --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateGlucoseValueTransaction.kt @@ -0,0 +1,15 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.transactions.Transaction + +/** + * Invalidates the GlucoseValue with the specified id + */ +class InvalidateGlucoseValueTransaction(val id: Long) : Transaction() { + override fun run() { + val glucoseValue = database.glucoseValueDao.findById(id) + ?: throw IllegalArgumentException("There is no such GlucoseValue with the specified ID.") + glucoseValue.isValid = false + database.glucoseValueDao.updateExistingEntry(glucoseValue) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTemporaryTargetTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTemporaryTargetTransaction.kt new file mode 100644 index 0000000000..7109fbf672 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/InvalidateTemporaryTargetTransaction.kt @@ -0,0 +1,10 @@ +package info.nightscout.androidaps.database.transactions + +class InvalidateTemporaryTargetTransaction(val id: Long) : Transaction() { + override fun run() { + val temporaryTarget = database.temporaryTargetDao.findById(id) + ?: throw IllegalArgumentException("There is no such TemporaryTarget with the specified ID.") + temporaryTarget.isValid = false + database.temporaryTargetDao.updateExistingEntry(temporaryTarget) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/Transaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/Transaction.kt new file mode 100644 index 0000000000..36d07a9926 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/Transaction.kt @@ -0,0 +1,18 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.DelegatedAppDatabase + +/** + * Base class for database transactions + * @param T The return type of the Transaction + */ +abstract class Transaction { + + /** + * Executes the Transaction + */ + internal abstract fun run(): T + + internal lateinit var database: DelegatedAppDatabase + +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateGlucoseValueTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateGlucoseValueTransaction.kt new file mode 100644 index 0000000000..8d6ce188be --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateGlucoseValueTransaction.kt @@ -0,0 +1,13 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.GlucoseValue + +/** + * Updates the GlucoseValue + */ +class UpdateGlucoseValueTransaction(val glucoseValue: GlucoseValue) : Transaction() { + + override fun run() { + database.glucoseValueDao.updateExistingEntry(glucoseValue) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateTemporaryTargetTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateTemporaryTargetTransaction.kt new file mode 100644 index 0000000000..0a9f140c20 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/UpdateTemporaryTargetTransaction.kt @@ -0,0 +1,13 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.TemporaryTarget + +/** + * Updates the TemporaryTarget + */ +class UpdateTemporaryTargetTransaction(private val temporaryTarget: TemporaryTarget) : Transaction() { + + override fun run() { + database.temporaryTargetDao.updateExistingEntry(temporaryTarget) + } +} \ No newline at end of file diff --git a/database/src/main/java/info/nightscout/androidaps/database/transactions/VersionChangeTransaction.kt b/database/src/main/java/info/nightscout/androidaps/database/transactions/VersionChangeTransaction.kt new file mode 100644 index 0000000000..d828e279b3 --- /dev/null +++ b/database/src/main/java/info/nightscout/androidaps/database/transactions/VersionChangeTransaction.kt @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.database.transactions + +import info.nightscout.androidaps.database.entities.VersionChange +import java.util.* + +class VersionChangeTransaction( + private val versionName: String, + private val versionCode: Int, + private val gitRemote: String?, + private val commitHash: String?) : Transaction() { + + override fun run() { + val current = database.versionChangeDao.getMostRecentVersionChange() + if (current == null + || current.versionName != versionName + || current.versionCode != versionCode + || current.gitRemote != gitRemote + || current.commitHash != commitHash) { + val currentTime = System.currentTimeMillis() + database.versionChangeDao.insert(VersionChange( + timestamp = System.currentTimeMillis(), + versionCode = versionCode, + versionName = versionName, + gitRemote = gitRemote, + commitHash = commitHash + )) + } + } + +} \ No newline at end of file diff --git a/database/src/test/java/info/nightscout/database/ExampleUnitTest.kt b/database/src/test/java/info/nightscout/database/ExampleUnitTest.kt new file mode 100644 index 0000000000..a0b6e3a55e --- /dev/null +++ b/database/src/test/java/info/nightscout/database/ExampleUnitTest.kt @@ -0,0 +1,18 @@ +package info.nightscout.database + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 4fb6743f5f..163be2365a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,3 @@ +include ':database' include ':app', ':wear', ':core', ':dana', ':danar', ':danars', ':rileylink', ':medtronic', ':omnipod'