diff --git a/CHANGELOG.md b/CHANGELOG.md index e45a34c9c03..33a974ec6aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ ### Internal +- Add `ReturnScore` table + +## 2026.03.02 + +### Internal + - Update `ci-checks.yml` & `story-link-check.sh` to verify valid jira reference - Add effect to fetch complete medical records - Bump sqlcipher to v4.13.0 @@ -24,6 +30,7 @@ ### Changes - Add `Sync Medical Records` button on setting page behind feature flag +- Increase the network read timeout to 45 seconds ## 2026.02.02 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9b51f3f1b2c..404ea7f120c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -330,6 +330,7 @@ dependencies { implementation(libs.kotlin.coroutines) implementation(libs.kotlin.coroutines.test) implementation(libs.kotlin.stdlib) + implementation(libs.kotlin.serialization) implementation(libs.logback.classic) diff --git a/app/schemas/org.simple.clinic.AppDatabase/123.json b/app/schemas/org.simple.clinic.AppDatabase/123.json new file mode 100644 index 00000000000..87abb44654f --- /dev/null +++ b/app/schemas/org.simple.clinic.AppDatabase/123.json @@ -0,0 +1,2285 @@ +{ + "formatVersion": 1, + "database": { + "version": 123, + "identityHash": "412ffbb3582e6c91acc665cc7fe5a566", + "entities": [ + { + "tableName": "Patient", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `addressUuid` TEXT NOT NULL, `fullName` TEXT NOT NULL, `gender` TEXT NOT NULL, `status` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, `recordedAt` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `reminderConsent` TEXT NOT NULL, `deletedReason` TEXT, `registeredFacilityId` TEXT, `assignedFacilityId` TEXT, `retainUntil` TEXT, `eligibleForReassignment` TEXT NOT NULL, `age_value` INTEGER, `age_updatedAt` TEXT, `dateOfBirth` TEXT, PRIMARY KEY(`uuid`), FOREIGN KEY(`addressUuid`) REFERENCES `PatientAddress`(`uuid`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "addressUuid", + "columnName": "addressUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "fullName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gender", + "columnName": "gender", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "recordedAt", + "columnName": "recordedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reminderConsent", + "columnName": "reminderConsent", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedReason", + "columnName": "deletedReason", + "affinity": "TEXT" + }, + { + "fieldPath": "registeredFacilityId", + "columnName": "registeredFacilityId", + "affinity": "TEXT" + }, + { + "fieldPath": "assignedFacilityId", + "columnName": "assignedFacilityId", + "affinity": "TEXT" + }, + { + "fieldPath": "retainUntil", + "columnName": "retainUntil", + "affinity": "TEXT" + }, + { + "fieldPath": "eligibleForReassignment", + "columnName": "eligibleForReassignment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ageDetails.ageValue", + "columnName": "age_value", + "affinity": "INTEGER" + }, + { + "fieldPath": "ageDetails.ageUpdatedAt", + "columnName": "age_updatedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "ageDetails.dateOfBirth", + "columnName": "dateOfBirth", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_Patient_addressUuid", + "unique": false, + "columnNames": [ + "addressUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_Patient_addressUuid` ON `${TABLE_NAME}` (`addressUuid`)" + }, + { + "name": "index_Patient_assignedFacilityId", + "unique": false, + "columnNames": [ + "assignedFacilityId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_Patient_assignedFacilityId` ON `${TABLE_NAME}` (`assignedFacilityId`)" + } + ], + "foreignKeys": [ + { + "table": "PatientAddress", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "addressUuid" + ], + "referencedColumns": [ + "uuid" + ] + } + ] + }, + { + "tableName": "PatientAddress", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `streetAddress` TEXT, `colonyOrVillage` TEXT, `zone` TEXT, `district` TEXT NOT NULL, `state` TEXT NOT NULL, `country` TEXT, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "streetAddress", + "columnName": "streetAddress", + "affinity": "TEXT" + }, + { + "fieldPath": "colonyOrVillage", + "columnName": "colonyOrVillage", + "affinity": "TEXT" + }, + { + "fieldPath": "zone", + "columnName": "zone", + "affinity": "TEXT" + }, + { + "fieldPath": "district", + "columnName": "district", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT" + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "PatientPhoneNumber", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `number` TEXT NOT NULL, `phoneType` TEXT NOT NULL, `active` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`), FOREIGN KEY(`patientUuid`) REFERENCES `Patient`(`uuid`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phoneType", + "columnName": "phoneType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "active", + "columnName": "active", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_PatientPhoneNumber_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_PatientPhoneNumber_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + } + ], + "foreignKeys": [ + { + "table": "Patient", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "patientUuid" + ], + "referencedColumns": [ + "uuid" + ] + } + ] + }, + { + "tableName": "BloodPressureMeasurement", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `userUuid` TEXT NOT NULL, `facilityUuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, `recordedAt` TEXT NOT NULL, `systolic` INTEGER NOT NULL, `diastolic` INTEGER NOT NULL, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userUuid", + "columnName": "userUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "facilityUuid", + "columnName": "facilityUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "recordedAt", + "columnName": "recordedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reading.systolic", + "columnName": "systolic", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reading.diastolic", + "columnName": "diastolic", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_BloodPressureMeasurement_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BloodPressureMeasurement_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + }, + { + "name": "index_BloodPressureMeasurement_facilityUuid", + "unique": false, + "columnNames": [ + "facilityUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BloodPressureMeasurement_facilityUuid` ON `${TABLE_NAME}` (`facilityUuid`)" + } + ] + }, + { + "tableName": "PrescribedDrug", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `dosage` TEXT, `rxNormCode` TEXT, `isDeleted` INTEGER NOT NULL, `isProtocolDrug` INTEGER NOT NULL, `patientUuid` TEXT NOT NULL, `facilityUuid` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `frequency` TEXT, `durationInDays` INTEGER, `teleconsultationId` TEXT, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dosage", + "columnName": "dosage", + "affinity": "TEXT" + }, + { + "fieldPath": "rxNormCode", + "columnName": "rxNormCode", + "affinity": "TEXT" + }, + { + "fieldPath": "isDeleted", + "columnName": "isDeleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isProtocolDrug", + "columnName": "isProtocolDrug", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "facilityUuid", + "columnName": "facilityUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "frequency", + "columnName": "frequency", + "affinity": "TEXT" + }, + { + "fieldPath": "durationInDays", + "columnName": "durationInDays", + "affinity": "INTEGER" + }, + { + "fieldPath": "teleconsultationId", + "columnName": "teleconsultationId", + "affinity": "TEXT" + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_PrescribedDrug_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_PrescribedDrug_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + }, + { + "name": "index_PrescribedDrug_facilityUuid", + "unique": false, + "columnNames": [ + "facilityUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_PrescribedDrug_facilityUuid` ON `${TABLE_NAME}` (`facilityUuid`)" + } + ] + }, + { + "tableName": "Facility", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `facilityType` TEXT, `streetAddress` TEXT, `villageOrColony` TEXT, `district` TEXT NOT NULL, `state` TEXT NOT NULL, `country` TEXT NOT NULL, `pinCode` TEXT, `protocolUuid` TEXT, `groupUuid` TEXT, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `deletedAt` TEXT, `syncGroup` TEXT NOT NULL, `location_latitude` REAL, `location_longitude` REAL, `config_diabetesManagementEnabled` INTEGER NOT NULL, `config_teleconsultationEnabled` INTEGER, `config_monthlyScreeningReportsEnabled` INTEGER, `config_monthlySuppliesReportsEnabled` INTEGER NOT NULL, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "facilityType", + "columnName": "facilityType", + "affinity": "TEXT" + }, + { + "fieldPath": "streetAddress", + "columnName": "streetAddress", + "affinity": "TEXT" + }, + { + "fieldPath": "villageOrColony", + "columnName": "villageOrColony", + "affinity": "TEXT" + }, + { + "fieldPath": "district", + "columnName": "district", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pinCode", + "columnName": "pinCode", + "affinity": "TEXT" + }, + { + "fieldPath": "protocolUuid", + "columnName": "protocolUuid", + "affinity": "TEXT" + }, + { + "fieldPath": "groupUuid", + "columnName": "groupUuid", + "affinity": "TEXT" + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "syncGroup", + "columnName": "syncGroup", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "location.latitude", + "columnName": "location_latitude", + "affinity": "REAL" + }, + { + "fieldPath": "location.longitude", + "columnName": "location_longitude", + "affinity": "REAL" + }, + { + "fieldPath": "config.diabetesManagementEnabled", + "columnName": "config_diabetesManagementEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "config.teleconsultationEnabled", + "columnName": "config_teleconsultationEnabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "config.monthlyScreeningReportsEnabled", + "columnName": "config_monthlyScreeningReportsEnabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "config.monthlySuppliesReportsEnabled", + "columnName": "config_monthlySuppliesReportsEnabled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "LoggedInUser", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `fullName` TEXT NOT NULL, `phoneNumber` TEXT NOT NULL, `pinDigest` TEXT NOT NULL, `status` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `loggedInStatus` TEXT NOT NULL, `registrationFacilityUuid` TEXT NOT NULL, `currentFacilityUuid` TEXT NOT NULL, `teleconsultPhoneNumber` TEXT, `capability_canTeleconsult` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "fullName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phoneNumber", + "columnName": "phoneNumber", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pinDigest", + "columnName": "pinDigest", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loggedInStatus", + "columnName": "loggedInStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "registrationFacilityUuid", + "columnName": "registrationFacilityUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currentFacilityUuid", + "columnName": "currentFacilityUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teleconsultPhoneNumber", + "columnName": "teleconsultPhoneNumber", + "affinity": "TEXT" + }, + { + "fieldPath": "capabilities.canTeleconsult", + "columnName": "capability_canTeleconsult", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "Appointment", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `facilityUuid` TEXT NOT NULL, `scheduledDate` TEXT NOT NULL, `status` TEXT NOT NULL, `cancelReason` TEXT, `remindOn` TEXT, `agreedToVisit` INTEGER, `appointmentType` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, `creationFacilityUuid` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "facilityUuid", + "columnName": "facilityUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "scheduledDate", + "columnName": "scheduledDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cancelReason", + "columnName": "cancelReason", + "affinity": "TEXT" + }, + { + "fieldPath": "remindOn", + "columnName": "remindOn", + "affinity": "TEXT" + }, + { + "fieldPath": "agreedToVisit", + "columnName": "agreedToVisit", + "affinity": "INTEGER" + }, + { + "fieldPath": "appointmentType", + "columnName": "appointmentType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "creationFacilityUuid", + "columnName": "creationFacilityUuid", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_Appointment_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_Appointment_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + }, + { + "name": "index_Appointment_creationFacilityUuid", + "unique": false, + "columnNames": [ + "creationFacilityUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_Appointment_creationFacilityUuid` ON `${TABLE_NAME}` (`creationFacilityUuid`)" + }, + { + "name": "index_Appointment_facilityUuid", + "unique": false, + "columnNames": [ + "facilityUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_Appointment_facilityUuid` ON `${TABLE_NAME}` (`facilityUuid`)" + } + ] + }, + { + "tableName": "MedicalHistory", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `diagnosedWithHypertension` TEXT NOT NULL, `isOnHypertensionTreatment` TEXT NOT NULL, `isOnDiabetesTreatment` TEXT NOT NULL, `hasHadHeartAttack` TEXT NOT NULL, `hasHadStroke` TEXT NOT NULL, `hasHadKidneyDisease` TEXT NOT NULL, `hasDiabetes` TEXT NOT NULL, `isSmoking` TEXT NOT NULL, `isUsingSmokelessTobacco` TEXT NOT NULL, `cholesterol_value` REAL, `hypertensionDiagnosedAt` TEXT, `diabetesDiagnosedAt` TEXT, `syncStatus` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "diagnosedWithHypertension", + "columnName": "diagnosedWithHypertension", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isOnHypertensionTreatment", + "columnName": "isOnHypertensionTreatment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isOnDiabetesTreatment", + "columnName": "isOnDiabetesTreatment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasHadHeartAttack", + "columnName": "hasHadHeartAttack", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasHadStroke", + "columnName": "hasHadStroke", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasHadKidneyDisease", + "columnName": "hasHadKidneyDisease", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "diagnosedWithDiabetes", + "columnName": "hasDiabetes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isSmoking", + "columnName": "isSmoking", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isUsingSmokelessTobacco", + "columnName": "isUsingSmokelessTobacco", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cholesterol", + "columnName": "cholesterol_value", + "affinity": "REAL" + }, + { + "fieldPath": "hypertensionDiagnosedAt", + "columnName": "hypertensionDiagnosedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "diabetesDiagnosedAt", + "columnName": "diabetesDiagnosedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_MedicalHistory_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_MedicalHistory_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + } + ] + }, + { + "tableName": "OngoingLoginEntry", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `phoneNumber` TEXT, `pin` TEXT, `fullName` TEXT, `pinDigest` TEXT, `registrationFacilityUuid` TEXT, `status` TEXT, `createdAt` TEXT, `updatedAt` TEXT, `teleconsultPhoneNumber` TEXT, `capability_canTeleconsult` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phoneNumber", + "columnName": "phoneNumber", + "affinity": "TEXT" + }, + { + "fieldPath": "pin", + "columnName": "pin", + "affinity": "TEXT" + }, + { + "fieldPath": "fullName", + "columnName": "fullName", + "affinity": "TEXT" + }, + { + "fieldPath": "pinDigest", + "columnName": "pinDigest", + "affinity": "TEXT" + }, + { + "fieldPath": "registrationFacilityUuid", + "columnName": "registrationFacilityUuid", + "affinity": "TEXT" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT" + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultPhoneNumber", + "columnName": "teleconsultPhoneNumber", + "affinity": "TEXT" + }, + { + "fieldPath": "capabilities.canTeleconsult", + "columnName": "capability_canTeleconsult", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "Protocol", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `followUpDays` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "followUpDays", + "columnName": "followUpDays", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "ProtocolDrug", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `protocolUuid` TEXT NOT NULL, `name` TEXT NOT NULL, `rxNormCode` TEXT, `dosage` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, `order` INTEGER NOT NULL, PRIMARY KEY(`uuid`), FOREIGN KEY(`protocolUuid`) REFERENCES `Protocol`(`uuid`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "protocolUuid", + "columnName": "protocolUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rxNormCode", + "columnName": "rxNormCode", + "affinity": "TEXT" + }, + { + "fieldPath": "dosage", + "columnName": "dosage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_ProtocolDrug_protocolUuid", + "unique": false, + "columnNames": [ + "protocolUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ProtocolDrug_protocolUuid` ON `${TABLE_NAME}` (`protocolUuid`)" + } + ], + "foreignKeys": [ + { + "table": "Protocol", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "protocolUuid" + ], + "referencedColumns": [ + "uuid" + ] + } + ] + }, + { + "tableName": "BusinessId", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `metaVersion` TEXT NOT NULL, `meta` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, `searchHelp` TEXT NOT NULL, `identifier` TEXT NOT NULL, `identifierType` TEXT NOT NULL, PRIMARY KEY(`uuid`), FOREIGN KEY(`patientUuid`) REFERENCES `Patient`(`uuid`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "metaDataVersion", + "columnName": "metaVersion", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "metaData", + "columnName": "meta", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "searchHelp", + "columnName": "searchHelp", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "identifier.value", + "columnName": "identifier", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "identifier.type", + "columnName": "identifierType", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_BusinessId_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BusinessId_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + }, + { + "name": "index_BusinessId_identifier", + "unique": false, + "columnNames": [ + "identifier" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BusinessId_identifier` ON `${TABLE_NAME}` (`identifier`)" + } + ], + "foreignKeys": [ + { + "table": "Patient", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "patientUuid" + ], + "referencedColumns": [ + "uuid" + ] + } + ] + }, + { + "tableName": "MissingPhoneReminder", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`patientUuid` TEXT NOT NULL, `remindedAt` TEXT NOT NULL, PRIMARY KEY(`patientUuid`))", + "fields": [ + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "remindedAt", + "columnName": "remindedAt", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "patientUuid" + ] + } + }, + { + "tableName": "BloodSugarMeasurements", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `recordedAt` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `userUuid` TEXT NOT NULL, `facilityUuid` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `reading_value` TEXT NOT NULL, `reading_type` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "recordedAt", + "columnName": "recordedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userUuid", + "columnName": "userUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "facilityUuid", + "columnName": "facilityUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reading.value", + "columnName": "reading_value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reading.type", + "columnName": "reading_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_BloodSugarMeasurements_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BloodSugarMeasurements_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + }, + { + "name": "index_BloodSugarMeasurements_facilityUuid", + "unique": false, + "columnNames": [ + "facilityUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BloodSugarMeasurements_facilityUuid` ON `${TABLE_NAME}` (`facilityUuid`)" + } + ] + }, + { + "tableName": "TextRecords", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `text` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "TeleconsultationFacilityInfo", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`teleconsultationFacilityId` TEXT NOT NULL, `facilityId` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, `syncStatus` TEXT NOT NULL, PRIMARY KEY(`teleconsultationFacilityId`))", + "fields": [ + { + "fieldPath": "teleconsultationFacilityId", + "columnName": "teleconsultationFacilityId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "facilityId", + "columnName": "facilityId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "teleconsultationFacilityId" + ] + } + }, + { + "tableName": "MedicalOfficer", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`medicalOfficerId` TEXT NOT NULL, `fullName` TEXT NOT NULL, `phoneNumber` TEXT NOT NULL, PRIMARY KEY(`medicalOfficerId`))", + "fields": [ + { + "fieldPath": "medicalOfficerId", + "columnName": "medicalOfficerId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "fullName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phoneNumber", + "columnName": "phoneNumber", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "medicalOfficerId" + ] + } + }, + { + "tableName": "TeleconsultationFacilityMedicalOfficersCrossRef", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`teleconsultationFacilityId` TEXT NOT NULL, `medicalOfficerId` TEXT NOT NULL, PRIMARY KEY(`teleconsultationFacilityId`, `medicalOfficerId`))", + "fields": [ + { + "fieldPath": "teleconsultationFacilityId", + "columnName": "teleconsultationFacilityId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "medicalOfficerId", + "columnName": "medicalOfficerId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "teleconsultationFacilityId", + "medicalOfficerId" + ] + } + }, + { + "tableName": "TeleconsultRecord", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `patientId` TEXT NOT NULL, `medicalOfficerId` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `request_requesterId` TEXT, `request_facilityId` TEXT, `request_requestedAt` TEXT, `request_requesterCompletionStatus` TEXT, `record_recordedAt` TEXT, `record_teleconsultationType` TEXT, `record_patientTookMedicines` TEXT, `record_patientConsented` TEXT, `record_medicalOfficerNumber` TEXT, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientId", + "columnName": "patientId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "medicalOfficerId", + "columnName": "medicalOfficerId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teleconsultRequestInfo.requesterId", + "columnName": "request_requesterId", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRequestInfo.facilityId", + "columnName": "request_facilityId", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRequestInfo.requestedAt", + "columnName": "request_requestedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRequestInfo.requesterCompletionStatus", + "columnName": "request_requesterCompletionStatus", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRecordInfo.recordedAt", + "columnName": "record_recordedAt", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRecordInfo.teleconsultationType", + "columnName": "record_teleconsultationType", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRecordInfo.patientTookMedicines", + "columnName": "record_patientTookMedicines", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRecordInfo.patientConsented", + "columnName": "record_patientConsented", + "affinity": "TEXT" + }, + { + "fieldPath": "teleconsultRecordInfo.medicalOfficerNumber", + "columnName": "record_medicalOfficerNumber", + "affinity": "TEXT" + }, + { + "fieldPath": "timestamp.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "Drug", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `category` TEXT, `frequency` TEXT, `composition` TEXT, `dosage` TEXT, `rxNormCode` TEXT, `protocol` TEXT NOT NULL, `common` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT" + }, + { + "fieldPath": "frequency", + "columnName": "frequency", + "affinity": "TEXT" + }, + { + "fieldPath": "composition", + "columnName": "composition", + "affinity": "TEXT" + }, + { + "fieldPath": "dosage", + "columnName": "dosage", + "affinity": "TEXT" + }, + { + "fieldPath": "rxNormCode", + "columnName": "rxNormCode", + "affinity": "TEXT" + }, + { + "fieldPath": "protocol", + "columnName": "protocol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "common", + "columnName": "common", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "CallResult", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `userId` TEXT NOT NULL, `patientId` TEXT, `facilityId` TEXT, `appointmentId` TEXT NOT NULL, `removeReason` TEXT, `outcome` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientId", + "columnName": "patientId", + "affinity": "TEXT" + }, + { + "fieldPath": "facilityId", + "columnName": "facilityId", + "affinity": "TEXT" + }, + { + "fieldPath": "appointmentId", + "columnName": "appointmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "removeReason", + "columnName": "removeReason", + "affinity": "TEXT" + }, + { + "fieldPath": "outcome", + "columnName": "outcome", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_CallResult_appointmentId", + "unique": false, + "columnNames": [ + "appointmentId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_CallResult_appointmentId` ON `${TABLE_NAME}` (`appointmentId`)" + } + ] + }, + { + "tableName": "PatientFts", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`uuid` TEXT NOT NULL, `fullName` TEXT NOT NULL, content=`Patient`)", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullName", + "columnName": "fullName", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "simple", + "tokenizerArgs": [], + "contentTable": "Patient", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [ + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientFts_BEFORE_UPDATE BEFORE UPDATE ON `Patient` BEGIN DELETE FROM `PatientFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientFts_BEFORE_DELETE BEFORE DELETE ON `Patient` BEGIN DELETE FROM `PatientFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientFts_AFTER_UPDATE AFTER UPDATE ON `Patient` BEGIN INSERT INTO `PatientFts`(`docid`, `uuid`, `fullName`) VALUES (NEW.`rowid`, NEW.`uuid`, NEW.`fullName`); END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientFts_AFTER_INSERT AFTER INSERT ON `Patient` BEGIN INSERT INTO `PatientFts`(`docid`, `uuid`, `fullName`) VALUES (NEW.`rowid`, NEW.`uuid`, NEW.`fullName`); END" + ] + }, + { + "tableName": "PatientPhoneNumberFts", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`patientUuid` TEXT NOT NULL, `number` TEXT NOT NULL, content=`PatientPhoneNumber`)", + "fields": [ + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "simple", + "tokenizerArgs": [], + "contentTable": "PatientPhoneNumber", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [ + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientPhoneNumberFts_BEFORE_UPDATE BEFORE UPDATE ON `PatientPhoneNumber` BEGIN DELETE FROM `PatientPhoneNumberFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientPhoneNumberFts_BEFORE_DELETE BEFORE DELETE ON `PatientPhoneNumber` BEGIN DELETE FROM `PatientPhoneNumberFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientPhoneNumberFts_AFTER_UPDATE AFTER UPDATE ON `PatientPhoneNumber` BEGIN INSERT INTO `PatientPhoneNumberFts`(`docid`, `patientUuid`, `number`) VALUES (NEW.`rowid`, NEW.`patientUuid`, NEW.`number`); END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientPhoneNumberFts_AFTER_INSERT AFTER INSERT ON `PatientPhoneNumber` BEGIN INSERT INTO `PatientPhoneNumberFts`(`docid`, `patientUuid`, `number`) VALUES (NEW.`rowid`, NEW.`patientUuid`, NEW.`number`); END" + ] + }, + { + "tableName": "BusinessIdFts", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`patientUuid` TEXT NOT NULL, `searchHelp` TEXT NOT NULL, content=`BusinessId`)", + "fields": [ + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "searchHelp", + "columnName": "searchHelp", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "simple", + "tokenizerArgs": [], + "contentTable": "BusinessId", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [ + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_BusinessIdFts_BEFORE_UPDATE BEFORE UPDATE ON `BusinessId` BEGIN DELETE FROM `BusinessIdFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_BusinessIdFts_BEFORE_DELETE BEFORE DELETE ON `BusinessId` BEGIN DELETE FROM `BusinessIdFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_BusinessIdFts_AFTER_UPDATE AFTER UPDATE ON `BusinessId` BEGIN INSERT INTO `BusinessIdFts`(`docid`, `patientUuid`, `searchHelp`) VALUES (NEW.`rowid`, NEW.`patientUuid`, NEW.`searchHelp`); END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_BusinessIdFts_AFTER_INSERT AFTER INSERT ON `BusinessId` BEGIN INSERT INTO `BusinessIdFts`(`docid`, `patientUuid`, `searchHelp`) VALUES (NEW.`rowid`, NEW.`patientUuid`, NEW.`searchHelp`); END" + ] + }, + { + "tableName": "PatientAddressFts", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`uuid` TEXT NOT NULL, `colonyOrVillage` TEXT, content=`PatientAddress`)", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "colonyOrVillage", + "columnName": "colonyOrVillage", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "simple", + "tokenizerArgs": [], + "contentTable": "PatientAddress", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [ + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientAddressFts_BEFORE_UPDATE BEFORE UPDATE ON `PatientAddress` BEGIN DELETE FROM `PatientAddressFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientAddressFts_BEFORE_DELETE BEFORE DELETE ON `PatientAddress` BEGIN DELETE FROM `PatientAddressFts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientAddressFts_AFTER_UPDATE AFTER UPDATE ON `PatientAddress` BEGIN INSERT INTO `PatientAddressFts`(`docid`, `uuid`, `colonyOrVillage`) VALUES (NEW.`rowid`, NEW.`uuid`, NEW.`colonyOrVillage`); END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_PatientAddressFts_AFTER_INSERT AFTER INSERT ON `PatientAddress` BEGIN INSERT INTO `PatientAddressFts`(`docid`, `uuid`, `colonyOrVillage`) VALUES (NEW.`rowid`, NEW.`uuid`, NEW.`colonyOrVillage`); END" + ] + }, + { + "tableName": "Questionnaire", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `questionnaire_type` TEXT NOT NULL, `layout` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`questionnaire_type`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "questionnaire_type", + "columnName": "questionnaire_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "layout", + "columnName": "layout", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "questionnaire_type" + ] + } + }, + { + "tableName": "QuestionnaireResponse", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `questionnaireId` TEXT NOT NULL, `questionnaireType` TEXT NOT NULL, `facilityId` TEXT NOT NULL, `lastUpdatedByUserId` TEXT, `content` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "questionnaireId", + "columnName": "questionnaireId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "questionnaireType", + "columnName": "questionnaireType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "facilityId", + "columnName": "facilityId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastUpdatedByUserId", + "columnName": "lastUpdatedByUserId", + "affinity": "TEXT" + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + } + }, + { + "tableName": "PatientAttribute", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `userUuid` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `height` REAL NOT NULL, `weight` REAL NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userUuid", + "columnName": "userUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "bmiReading.height", + "columnName": "height", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "bmiReading.weight", + "columnName": "weight", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_PatientAttribute_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_PatientAttribute_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + } + ] + }, + { + "tableName": "CVDRisk", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `syncStatus` TEXT NOT NULL, `min` INTEGER NOT NULL, `max` INTEGER NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncStatus", + "columnName": "syncStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "riskScore.min", + "columnName": "min", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "riskScore.max", + "columnName": "max", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_CVDRisk_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_CVDRisk_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + } + ] + }, + { + "tableName": "ReturnScore", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uuid` TEXT NOT NULL, `patientUuid` TEXT NOT NULL, `scoreType` TEXT NOT NULL, `scoreValue` REAL NOT NULL, `createdAt` TEXT NOT NULL, `updatedAt` TEXT NOT NULL, `deletedAt` TEXT, PRIMARY KEY(`uuid`))", + "fields": [ + { + "fieldPath": "uuid", + "columnName": "uuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientUuid", + "columnName": "patientUuid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "scoreType", + "columnName": "scoreType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "scoreValue", + "columnName": "scoreValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "timestamps.createdAt", + "columnName": "createdAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.updatedAt", + "columnName": "updatedAt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamps.deletedAt", + "columnName": "deletedAt", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "uuid" + ] + }, + "indices": [ + { + "name": "index_ReturnScore_patientUuid", + "unique": false, + "columnNames": [ + "patientUuid" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ReturnScore_patientUuid` ON `${TABLE_NAME}` (`patientUuid`)" + } + ] + } + ], + "views": [ + { + "viewName": "PatientSearchResult", + "createSql": "CREATE VIEW `${VIEW_NAME}` AS SELECT P.uuid, P.fullName, P.gender, P.dateOfBirth, P.age_value, P.age_updatedAt,\n P.assignedFacilityId, P.status, P.eligibleForReassignment,\n PA.uuid addr_uuid, PA.streetAddress addr_streetAddress, PA.colonyOrVillage addr_colonyOrVillage, PA.zone addr_zone, PA.district addr_district,\n PA.state addr_state, PA.country addr_country,\n PA.createdAt addr_createdAt, PA.updatedAt addr_updatedAt, PA.deletedAt addr_deletedAt,\n PP.number phoneNumber,\n B.identifier id_identifier, B.identifierType id_identifierType, B.searchHelp identifierSearchHelp, AF.name assignedFacilityName\n FROM Patient P\n INNER JOIN PatientAddress PA ON PA.uuid = P.addressUuid\n LEFT JOIN PatientPhoneNumber PP ON PP.patientUuid = P.uuid\n LEFT JOIN Facility AF ON AF.uuid = P.assignedFacilityId\n LEFT JOIN BusinessId B ON B.patientUuid = P.uuid\n WHERE P.deletedAt IS NULL" + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '412ffbb3582e6c91acc665cc7fe5a566')" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/org/simple/clinic/storage/migrations/Migration123AndroidTest.kt b/app/src/androidTest/java/org/simple/clinic/storage/migrations/Migration123AndroidTest.kt new file mode 100644 index 00000000000..5499ab96b3b --- /dev/null +++ b/app/src/androidTest/java/org/simple/clinic/storage/migrations/Migration123AndroidTest.kt @@ -0,0 +1,19 @@ +package org.simple.clinic.storage.migrations + +import org.junit.Test +import org.simple.clinic.assertIndexDoesNotExist +import org.simple.clinic.assertIndexExists +import org.simple.clinic.assertTableDoesNotExist +import org.simple.clinic.assertTableExists + +class Migration123AndroidTest : BaseDatabaseMigrationTest(122, 123) { + + @Test + fun migration_123_should_generate_the_ReturnScore_table() { + before.assertTableDoesNotExist("ReturnScore") + before.assertIndexDoesNotExist("index_ReturnScore_patientUuid") + + after.assertTableExists("ReturnScore") + after.assertIndexExists("index_ReturnScore_patientUuid") + } +} diff --git a/app/src/main/java/org/simple/clinic/AppDatabase.kt b/app/src/main/java/org/simple/clinic/AppDatabase.kt index bb94adb128f..126206f7091 100644 --- a/app/src/main/java/org/simple/clinic/AppDatabase.kt +++ b/app/src/main/java/org/simple/clinic/AppDatabase.kt @@ -49,9 +49,11 @@ import org.simple.clinic.protocol.Protocol import org.simple.clinic.protocol.ProtocolDrug import org.simple.clinic.questionnaire.Questionnaire import org.simple.clinic.questionnaire.QuestionnaireType +import org.simple.clinic.returnscore.ReturnScore import org.simple.clinic.questionnaire.component.BaseComponentData import org.simple.clinic.questionnaire.component.properties.InputFieldType import org.simple.clinic.questionnaireresponse.QuestionnaireResponse +import org.simple.clinic.returnscore.ScoreType import org.simple.clinic.storage.text.TextRecord import org.simple.clinic.summary.addphone.MissingPhoneReminder import org.simple.clinic.summary.teleconsultation.sync.MedicalOfficer @@ -105,12 +107,13 @@ import org.simple.clinic.patient.Answer as PatientAnswer Questionnaire::class, QuestionnaireResponse::class, PatientAttribute::class, - CVDRisk::class + CVDRisk::class, + ReturnScore::class, ], views = [ PatientSearchResult::class ], - version = 122, + version = 123, exportSchema = true ) @TypeConverters( @@ -148,6 +151,7 @@ import org.simple.clinic.patient.Answer as PatientAnswer MapRoomTypeConverter::class, PatientAnswer.RoomTypeConverter::class, CVDRiskRange.RoomTypeConverter::class, + ScoreType.RoomTypeConverter::class, ) abstract class AppDatabase : RoomDatabase() { @@ -209,6 +213,8 @@ abstract class AppDatabase : RoomDatabase() { abstract fun cvdRiskDao(): CVDRisk.RoomDao + abstract fun returnScoreDao(): ReturnScore.RoomDao + fun clearAppData() { runInTransaction { patientDao().clear() @@ -228,6 +234,7 @@ abstract class AppDatabase : RoomDatabase() { questionnaireResponseDao().clear() patientAttributeDao().clear() cvdRiskDao().clear() + returnScoreDao().clear() } } @@ -258,7 +265,8 @@ abstract class AppDatabase : RoomDatabase() { purgeUnnecessaryMedicalHistories() + purgeUnnecessaryPrescriptions() + purgeUnnecessaryCallResults() + - purgeUnnecessaryQuestionnaireResponses() + purgeUnnecessaryQuestionnaireResponses() + + purgeUnnecessaryReturnScores() } } @@ -316,6 +324,10 @@ abstract class AppDatabase : RoomDatabase() { questionnaireResponseDao().purgeDeleted() } + private fun purgeUnnecessaryReturnScores(): Int { + return returnScoreDao().purgeDeleted() + } + private fun vacuumDatabase() { val db = openHelper.writableDatabase diff --git a/app/src/main/java/org/simple/clinic/di/network/NetworkModule.kt b/app/src/main/java/org/simple/clinic/di/network/NetworkModule.kt index 67d939d1237..a30b13eaf3f 100644 --- a/app/src/main/java/org/simple/clinic/di/network/NetworkModule.kt +++ b/app/src/main/java/org/simple/clinic/di/network/NetworkModule.kt @@ -32,6 +32,7 @@ import org.simple.clinic.questionnaire.component.properties.InputFieldType import org.simple.clinic.questionnaire.component.properties.InputFieldViewType import org.simple.clinic.questionnaireresponse.sync.QuestionnaireResponsePayload import org.simple.clinic.remoteconfig.ConfigReader +import org.simple.clinic.returnscore.ScoreType import org.simple.clinic.scanid.IndiaNHIDDateOfBirth import org.simple.clinic.scanid.IndiaNHIDDateOfBirthMoshiAdapter import org.simple.clinic.scanid.IndiaNHIDGender @@ -98,6 +99,7 @@ class NetworkModule { .add(InputFieldViewType.MoshiTypeAdapter()) .add(PatientAnswer.MoshiTypeAdapter()) .add(CVDRiskRange.MoshiTypeAdapter()) + .add(ScoreType.MoshiTypeAdapter()) .build() val patientPayloadNullSerializingAdapter = moshi.adapter(PatientPayload::class.java).serializeNulls() @@ -123,7 +125,7 @@ class NetworkModule { // When syncing large amounts of data, the default read timeout(10s) has been seen to // timeout frequently for larger models. Through trial and error, 15s was found to be a // good number for syncing large batch sizes. - readTimeout(configReader.long("networkmodule_read_timeout", default = 30L), TimeUnit.SECONDS) + readTimeout(configReader.long("networkmodule_read_timeout", default = 45L), TimeUnit.SECONDS) } .build() } diff --git a/app/src/main/java/org/simple/clinic/returnscore/ReturnScore.kt b/app/src/main/java/org/simple/clinic/returnscore/ReturnScore.kt new file mode 100644 index 00000000000..711eb33fe08 --- /dev/null +++ b/app/src/main/java/org/simple/clinic/returnscore/ReturnScore.kt @@ -0,0 +1,53 @@ +package org.simple.clinic.returnscore + +import android.os.Parcelable +import androidx.room.Dao +import androidx.room.Embedded +import androidx.room.Entity +import androidx.room.Index +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.PrimaryKey +import androidx.room.Query +import io.reactivex.Flowable +import kotlinx.parcelize.Parcelize +import org.simple.clinic.storage.Timestamps +import java.util.UUID + +@Entity(tableName = "ReturnScore", + indices = [ + Index("patientUuid") + ]) +@Parcelize +data class ReturnScore( + @PrimaryKey + val uuid: UUID, + + val patientUuid: UUID, + + val scoreType: ScoreType, + + val scoreValue: Float, + + @Embedded + val timestamps: Timestamps, +) : Parcelable { + + @Dao + interface RoomDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun save(returnScores: List) + + @Query("SELECT * FROM ReturnScore WHERE deletedAt IS NULL") + fun getAll(): Flowable> + + @Query("DELETE FROM returnscore") + fun clear(): Int + + @Query(""" + DELETE FROM ReturnScore + WHERE deletedAt IS NOT NULL + """) + fun purgeDeleted(): Int + } +} diff --git a/app/src/main/java/org/simple/clinic/returnscore/ScoreType.kt b/app/src/main/java/org/simple/clinic/returnscore/ScoreType.kt new file mode 100644 index 00000000000..1dcd3d5643b --- /dev/null +++ b/app/src/main/java/org/simple/clinic/returnscore/ScoreType.kt @@ -0,0 +1,49 @@ +package org.simple.clinic.returnscore + +import android.os.Parcelable +import androidx.annotation.VisibleForTesting +import androidx.room.TypeConverter +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import kotlinx.parcelize.Parcelize +import org.simple.clinic.util.room.SafeEnumTypeAdapter + +sealed class ScoreType : Parcelable { + object TypeAdapter : SafeEnumTypeAdapter( + knownMappings = mapOf( + LikelyToReturnScoreType to "likely_to_return", + ), + unknownStringToEnumConverter = ::Unknown, + unknownEnumToStringConverter = { (it as Unknown).actualValue } + ) + + class RoomTypeConverter { + + @TypeConverter + fun toEnum(value: String?): ScoreType? = TypeAdapter.toEnum(value) + + @TypeConverter + fun fromEnum(scoreType: ScoreType?): String? = TypeAdapter.fromEnum(scoreType) + } + + class MoshiTypeAdapter { + + @FromJson + fun fromJson(value: String?): ScoreType? = TypeAdapter.toEnum(value) + + @ToJson + fun toJson(scoreType: ScoreType?): String? = TypeAdapter.fromEnum(scoreType) + } + + companion object { + @VisibleForTesting + fun random(): ScoreType = TypeAdapter.knownMappings.keys.shuffled().first() + } +} + +@Parcelize +data object LikelyToReturnScoreType : ScoreType() + +@Parcelize +data class Unknown(val actualValue: String) : ScoreType() + diff --git a/app/src/main/java/org/simple/clinic/storage/migrations/Migration_123.kt b/app/src/main/java/org/simple/clinic/storage/migrations/Migration_123.kt new file mode 100644 index 00000000000..4e50a1a3b6b --- /dev/null +++ b/app/src/main/java/org/simple/clinic/storage/migrations/Migration_123.kt @@ -0,0 +1,28 @@ +package org.simple.clinic.storage.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase +import org.simple.clinic.storage.inTransaction +import javax.inject.Inject + +@Suppress("ClassName") +class Migration_123 @Inject constructor() : Migration(122, 123) { + override fun migrate(db: SupportSQLiteDatabase) { + db.inTransaction { + execSQL(""" + CREATE TABLE IF NOT EXISTS "ReturnScore" ( + "uuid" TEXT NOT NULL, + "patientUuid" TEXT NOT NULL, + "scoreType" TEXT NOT NULL, + "scoreValue" REAL NOT NULL, + "createdAt" TEXT NOT NULL, + "updatedAt" TEXT NOT NULL, + "deletedAt" TEXT, + PRIMARY KEY("uuid") + ) + """) + + execSQL("CREATE INDEX IF NOT EXISTS `index_ReturnScore_patientUuid` ON `ReturnScore` (`patientUuid`)") + } + } +} diff --git a/app/src/main/java/org/simple/clinic/storage/migrations/RoomMigrationsModule.kt b/app/src/main/java/org/simple/clinic/storage/migrations/RoomMigrationsModule.kt index 0d66b164cc3..a315d83efc9 100644 --- a/app/src/main/java/org/simple/clinic/storage/migrations/RoomMigrationsModule.kt +++ b/app/src/main/java/org/simple/clinic/storage/migrations/RoomMigrationsModule.kt @@ -128,6 +128,7 @@ class RoomMigrationsModule { migration120: Migration_120, migration121: Migration_121, migration122: Migration_122, + migration123: Migration_123, ): List { return listOf( migration_3_4, @@ -249,6 +250,7 @@ class RoomMigrationsModule { migration120, migration121, migration122, + migration123 ) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9bce57d85e5..ba78b72494f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ chucker = "4.3.0" dagger = "2.59.1" kotlin = "2.3.10" +kotlinx-serialization = "1.10.0" ksp = "2.3.5" @@ -127,6 +128,7 @@ kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx2", v kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk7", version.ref = "kotlin" } kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } +kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } leakcanary = "com.squareup.leakcanary:leakcanary-android:2.14"