From d651a0d9ec6f5c09cf9a84aba199d4fcfd71c237 Mon Sep 17 00:00:00 2001 From: hue Date: Thu, 3 Jul 2025 16:09:59 -0400 Subject: [PATCH 1/6] Bump version --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a28b4feb..75b78d51 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,7 +14,7 @@ plugins { android { defaultConfig { - val buildVersion = 253 + val buildVersion = 254 applicationId = "com.crisiscleanup" versionCode = buildVersion versionName = "0.9.${buildVersion - 168}" From b8fdc10aaf1e68c3c952cd027cbb4a972692a624 Mon Sep 17 00:00:00 2001 From: hue Date: Tue, 8 Jul 2025 13:34:01 -0400 Subject: [PATCH 2/6] Update clear data timing --- .../data/repository/AppDataManagementRepository.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/data/src/main/java/com/crisiscleanup/core/data/repository/AppDataManagementRepository.kt b/core/data/src/main/java/com/crisiscleanup/core/data/repository/AppDataManagementRepository.kt index f85142a8..751fd887 100644 --- a/core/data/src/main/java/com/crisiscleanup/core/data/repository/AppDataManagementRepository.kt +++ b/core/data/src/main/java/com/crisiscleanup/core/data/repository/AppDataManagementRepository.kt @@ -109,18 +109,18 @@ class CrisisCleanupDataManagementRepository @Inject constructor( clearingAppDataStep.value = ClearAppDataStep.StopSyncPull stopSyncPull() - for (i in 0..9) { - TimeUnit.SECONDS.sleep(6) + for (i in 0..19) { + TimeUnit.SECONDS.sleep(3) if (isSyncPullStopped()) { break } } clearingAppDataStep.value = ClearAppDataStep.ClearData - for (i in 0..<3) { + for (i in 0..<6) { clearPersistedAppData() - TimeUnit.SECONDS.sleep(2) + TimeUnit.SECONDS.sleep(1) if (isPersistedAppDataCleared()) { break } @@ -178,5 +178,7 @@ class CrisisCleanupDataManagementRepository @Inject constructor( } private fun isPersistedAppDataCleared() = - incidentsRepository.incidentCount == 0L && worksiteChangeRepository.worksiteChangeCount == 0L && incidentDataSyncParameterDao.getSyncStatCount() == 0 + incidentsRepository.incidentCount == 0L && + worksiteChangeRepository.worksiteChangeCount == 0L && + incidentDataSyncParameterDao.getSyncStatCount() == 0 } From 20845be8829bf0b715fe53269de1c031db94767e Mon Sep 17 00:00:00 2001 From: hue Date: Thu, 10 Jul 2025 13:37:54 -0400 Subject: [PATCH 3/6] Improve phone number detection --- .../core/common/PhoneNumberUtil.kt | 158 ++++++++++++--- .../core/common/PhoneNumberUtilTest.kt | 191 +++++++++++++++--- 2 files changed, 291 insertions(+), 58 deletions(-) diff --git a/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt b/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt index d5b45bae..60bb384f 100644 --- a/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt +++ b/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt @@ -1,53 +1,145 @@ package com.crisiscleanup.core.common +import androidx.annotation.VisibleForTesting + object PhoneNumberUtil { - private val bracketsDashRegex = """[()-]""".toRegex() - private val letterRegex = """[a-zA-Z]""".toRegex() - private val twoPlusSpacesRegex = """\s{2,}""".toRegex() - private val nonNumberRegex = """\D""".toRegex() + private val noNumbersPattern = """^\D+$""".toRegex() - private val straightDigitsRegex = """^\d{10,11}$""".toRegex() - private val threeThreeFourDigitsRegex = """^\d{3} \d{3} \d{4}$""".toRegex() - private val areaCodeNumberRegex = """^\d{3} \d{7}$""".toRegex() - private val twoPhoneNumbersRegex = """^(\d{10,11})\D+(\d{10,11})$""".toRegex() + private val isTenDigitNumberPattern = """^\s*\d{10}\s*$""".toRegex() + private val isOneTenDigitNumberPattern = """^\s*1\d{10}\s*$""".toRegex() - fun getPhoneNumbers(possiblePhoneNumbers: List) = possiblePhoneNumbers - .filter { it?.isNotBlank() == true } - .map { it!! } - .map { phoneIn -> - val filtered = phoneIn.trim() - val cleaned = filtered.replace(bracketsDashRegex, "") - .replace(letterRegex, " ") - .replace(twoPlusSpacesRegex, " ") - .trim() + private val inParenthesisPattern = """\((\d{3})\)""".toRegex() + private val leadingOnePattern = """(?:^|\b)\+?1\s""".toRegex() + private val compact334DelimiterPattern = + """(?:^|\b)1?(\d{3})(.)(\d{3})\2(\d{4})(?:$|\b)""".toRegex() + private val compact334SpacePattern = + """(?:^|\b)1?(\d{3})\s+(\d{3})\s+(\d{4})(?:$|\b)""".toRegex() + private val digitDashDigitPattern = """(\d)-(\d)""".toRegex() + private val digitEndParenthesisDigitPattern = """(\d)\) (\d)""".toRegex() + private val compact37Pattern = """(?:^|\b)1?(\d{3})[.-]?\s(\d{7})(?:$|\b)""".toRegex() + private val compact64Pattern = """(?:^|\b)1?(\d{6})[.-]?\s(\d{4})(?:$|\b)""".toRegex() + private val leadingOnePostfixPattern = """(?:^|\b)1(?:- )?(\d{10})(?:$|\b)""".toRegex() + private val nonNumericEndsPattern = """^\D*\b(\d{10})\b\D*$""".toRegex() + private val repeatingNumbersPattern = """\b(\d)\1{4,}\b""".toRegex() + private val shortWordsPattern = """\b[a-zA-Z]{3,}\b""".toRegex() + + private val digitSequencePattern = """(?:^|\b)1?(\d{9,16})(?:$|\D+)""".toRegex() + private val separated37Pattern = """(?:^|\b)(\d{3})[. -](\d{7})(?:$|\b)""".toRegex() + private val nonDigitPattern = """\D""".toRegex(RegexOption.MULTILINE) + + private val String.exactTenDigits: String? + get() { + if (isBlank()) { + return "" + } + if (isOneTenDigitNumberPattern.matches(this)) { + return this.trim().substring(1) + } + if (isTenDigitNumberPattern.matches(this)) { + return this.trim() + } + return null + } + + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun parsePhoneNumbers(raw: String): ParsedPhoneNumber? { + if (raw.trim().length < 6) { + return null + } + + fun singleParsedNumber(result: String) = + ParsedPhoneNumber(raw, listOf(result.trim())) + + raw.exactTenDigits?.let { + return singleParsedNumber(it) + } + + if (noNumbersPattern.matches(raw)) { + return null + } - if (cleaned.isBlank()) { - return@map ParsedPhoneNumber(phoneIn, emptyList()) + val unparenthesized = raw.replace(inParenthesisPattern, "$1") + val leadingOneTrimmed = unparenthesized.replace(leadingOnePattern, "") + val threeThreeFourUndelimited = + leadingOneTrimmed.replace(compact334DelimiterPattern, " $1$3$4 ") + .also { + it.exactTenDigits?.let { tenDigits -> + return singleParsedNumber(tenDigits) + } + } + + val threeThreeFourUnspaced = + threeThreeFourUndelimited.replace(compact334SpacePattern, " $1$2$3 ") + val dashesRemoved = threeThreeFourUnspaced.replace(digitDashDigitPattern, "$1$2") + val endParenthesisRemoved = dashesRemoved.replace(digitEndParenthesisDigitPattern, "$1$2") + .also { + it.exactTenDigits?.let { tenDigits -> + return singleParsedNumber(tenDigits) + } } - if (straightDigitsRegex.matches(cleaned)) { - return@map ParsedPhoneNumber(phoneIn, listOf(cleaned)) + val threeSevenCompacted = endParenthesisRemoved.replace(compact37Pattern, " $1$2 ") + .also { + it.exactTenDigits?.let { tenDigits -> + return singleParsedNumber(tenDigits) + } } - if (threeThreeFourDigitsRegex.matches(cleaned) || - areaCodeNumberRegex.matches(cleaned) - ) { - val parsedNumber = cleaned.replace(" ", "") - return@map ParsedPhoneNumber(phoneIn, listOf(parsedNumber)) + val sixFourCompacted = threeSevenCompacted.replace(compact64Pattern, " $1$2 ") + val onePopped = sixFourCompacted.replace(leadingOnePostfixPattern, "$1") + val nonNumericEnds = onePopped.replace(nonNumericEndsPattern, "$1") + .also { + it.exactTenDigits?.let { tenDigits -> + return singleParsedNumber(tenDigits) + } } - twoPhoneNumbersRegex.matchEntire(cleaned)?.let { - val parsedNumbers = listOf(it.groupValues[1], it.groupValues[2]) - return@map ParsedPhoneNumber(phoneIn, parsedNumbers) + val repeatNumbersRemoved = nonNumericEnds.replace(repeatingNumbersPattern, "") + val noShortWords = repeatNumbersRemoved.replace(shortWordsPattern, " ") + + fun getMatches( + pattern: Regex, + s: String, + matchMaker: (MatchResult) -> String = { it.groupValues[1] }, + ): ParsedPhoneNumber? { + val patternMatches = pattern.findAll(s) + if (patternMatches.any()) { + val matches = patternMatches.map(matchMaker) + val matchList = matches.toList() + return if (matchList.size > 1) { + ParsedPhoneNumber(raw, matches.toList()) + } else { + singleParsedNumber(matches.first()) + } } + return null + } - val onlyNumbers = cleaned.replace(nonNumberRegex, "") - if (straightDigitsRegex.matches(onlyNumbers)) { - return@map ParsedPhoneNumber(phoneIn, listOf(onlyNumbers)) + getMatches(digitSequencePattern, noShortWords)?.let { + return it + } + + if (noShortWords.trim().length in 10..15) { + if (noShortWords.length <= 12) { + separated37Pattern.find(noShortWords)?.let { + return singleParsedNumber("${it.groupValues[1]}${it.groupValues[2]}") + } } - return@map ParsedPhoneNumber(phoneIn, emptyList()) + val onlyNumbers = noShortWords.replace(nonDigitPattern, "") + if (onlyNumbers.length in 9..11) { + return singleParsedNumber(onlyNumbers) + } } + + return null + } + + fun getPhoneNumbers(possiblePhoneNumbers: List) = possiblePhoneNumbers + .asSequence() + .mapNotNull { it } + .mapNotNull(::parsePhoneNumbers) + .toList() } data class ParsedPhoneNumber( diff --git a/core/common/src/test/java/com/crisiscleanup/core/common/PhoneNumberUtilTest.kt b/core/common/src/test/java/com/crisiscleanup/core/common/PhoneNumberUtilTest.kt index df81ba49..c34aaf2e 100644 --- a/core/common/src/test/java/com/crisiscleanup/core/common/PhoneNumberUtilTest.kt +++ b/core/common/src/test/java/com/crisiscleanup/core/common/PhoneNumberUtilTest.kt @@ -5,46 +5,187 @@ import kotlin.test.assertEquals class PhoneNumberUtilTest { @Test - fun emptyPhoneNumbers() { - val actual = PhoneNumberUtil.getPhoneNumbers(listOf("", " ")) - assertEquals(emptyList(), actual) + fun invalidPhoneNumbers() { + val inputs = listOf( + "", + " ", + " 12345 ", + " no numbers", + ) + for (input in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(null, actual) + } + } + + @Test + fun tenDigitNumberExactly() { + val inputs = listOf( + "1234567890", + " 1234567890", + "1234567890 ", + " 1234567890 ", + ) + for (input in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(listOf("1234567890"), actual) + } + } + + @Test + fun noCompaction() { + val inputs = listOf( + " (234)5678901 ", + "(234)5678901", + " 1(234)5678901", + "12345678901 ", + ) + for (input in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(listOf("2345678901"), actual) + } + } + + @Test + fun compact334() { + val inputs = listOf( + "234 567 8901", + "234-567-8901", + "234.567.8901", + "1234 567 8901", + "1234-567-8901", + "1234.567.8901", + "1234.567.8901", + "(234).567.8901", + "1(234).567.8901", + "234 567 8901 ", + " 234 567 8901", + " 234 567 8901 ", + "1234 567 8901 ", + ) + for (input in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(listOf("2345678901"), actual) + } + } + + @Test + fun dashParenthesis() { + val inputs = listOf( + "234567-8901", + "234-5678901", + "234) 567-8901", + ) + for (input in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(listOf("2345678901"), actual) + } } @Test - fun tenElevenDigitPhoneNumbers() { - val actual = PhoneNumberUtil.getPhoneNumbers(listOf("1234567890", "11234567890")) - val expected = listOf( - ParsedPhoneNumber("1234567890", listOf("1234567890")), - ParsedPhoneNumber("11234567890", listOf("11234567890")), + fun nonNumeric3764() { + val inputs = listOf( + "234 5678901", + "1234 5678901", + "something 1234 5678901-cell", + "+234 5678901 (air)", + "2345678901 a number", + "a 1234 5678901 b", + "234567 8901", + "something 234567 8901-cell", + "a 234567 8901 b", + "1234567 8901", + "12345678901 for anyone", ) - assertEquals(expected, actual) + for (input in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(listOf("2345678901"), actual) + } } @Test - fun commonSpacedPhoneNumbers() { - val actual = PhoneNumberUtil.getPhoneNumbers(listOf("123 456 7890", "123 4567890")) - val expected = listOf( - ParsedPhoneNumber("123 456 7890", listOf("1234567890")), - ParsedPhoneNumber("123 4567890", listOf("1234567890")), + fun possibleMultiple() { + val inputs = mapOf( + "23456789012" to listOf("23456789012"), + "1\u202A2345678901" to listOf("2345678901"), + "2345678901 or 3456789012" to listOf( + "2345678901", + "3456789012", + ), + "234567890" to listOf("234567890"), + "234567890-" to listOf("234567890"), + "2345678901 . 4282 M-F" to listOf("2345678901"), + "2345678901 / 3456789012" to listOf( + "2345678901", + "3456789012", + ), + "2345678901 or 3456789012" to listOf( + "2345678901", + "3456789012", + ), + "1.7068339198" to listOf("7068339198"), + "(23456789012" to listOf("23456789012"), + "18002345678901" to listOf("8002345678901"), + "2345678901 1st" to listOf("2345678901"), + "2345678901 9 0" to listOf("2345678901"), + "2345678901 ( be 3456789012)" to listOf( + "2345678901", + "3456789012", + ), + "2345678901/3456789012" to listOf( + "2345678901", + "3456789012", + ), + " 2345678901 or 3456789012 " to listOf( + "2345678901", + "3456789012", + ), + "2345678901/ 3456789012 ( )" to listOf( + "2345678901", + "3456789012", + ), + "2345678901/3456789012/4567891234" to listOf( + "2345678901", + "3456789012", + "4567891234", + ), + "2345678901, 3456789012, 4567891234 \n" to listOf( + "2345678901", + "3456789012", + "4567891234", + ), + "1234567890r9 " to listOf("234567890"), + "2345678901 x558 " to listOf("2345678901"), ) - assertEquals(expected, actual) + for ((input, expected) in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(expected, actual, input) + } } @Test - fun doublePhoneNumber() { - val actual = PhoneNumberUtil.getPhoneNumbers(listOf("1234567890dgk e*11234567890")) - val expected = listOf( - ParsedPhoneNumber("1234567890dgk e*11234567890", listOf("1234567890", "11234567890")), + fun dotDelimited11() { + val inputs = listOf( + "234.5678901", + "(234.5678901", ) - assertEquals(expected, actual) + for (input in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers + assertEquals(listOf("2345678901"), actual) + } } @Test - fun onlyNumbers() { - val actual = PhoneNumberUtil.getPhoneNumbers(listOf("1-2/3a4.5-6:7890")) - val expected = listOf( - ParsedPhoneNumber("1-2/3a4.5-6:7890", listOf("1234567890")), + fun mostlyNumbers() { + val inputs = mapOf( + "234 567- 8901- " to "2345678901", + "1234*5678901" to "12345678901", + "123 4567 8901" to "12345678901", + "123456 78901" to "12345678901", ) - assertEquals(expected, actual) + for ((input, expected) in inputs) { + val actual = PhoneNumberUtil.parsePhoneNumbers(input)?.parsedNumbers?.first() + assertEquals(expected, actual, input) + } } } From 44fed339024d648d7d6d7720aa388c4bd61b6a79 Mon Sep 17 00:00:00 2001 From: hue Date: Thu, 10 Jul 2025 15:12:20 -0400 Subject: [PATCH 4/6] Update phone data for better searching --- .../core/common/PhoneNumberUtil.kt | 40 + .../core/data/model/NetworkWorksite.kt | 5 + .../46.json | 3379 +++++++++++++++++ .../core/database/dao/WorksiteDaoTest.kt | 3 + .../core/database/CrisisCleanupDatabase.kt | 4 +- .../core/database/DatabaseMigrations.kt | 7 + .../core/database/dao/WorksiteDao.kt | 14 +- .../core/database/dao/WorksiteDaoPlus.kt | 1 + .../core/database/dao/fts/WorksiteTextFts.kt | 9 +- .../core/database/model/Worksite.kt | 2 + .../core/database/model/WorksiteEntity.kt | 4 +- .../core/model/data/IncidentDataSyncStats.kt | 2 +- 12 files changed, 3456 insertions(+), 14 deletions(-) create mode 100644 core/database/schemas/com.crisiscleanup.core.database.CrisisCleanupDatabase/46.json diff --git a/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt b/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt index 60bb384f..2bacd614 100644 --- a/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt +++ b/core/common/src/main/java/com/crisiscleanup/core/common/PhoneNumberUtil.kt @@ -1,6 +1,7 @@ package com.crisiscleanup.core.common import androidx.annotation.VisibleForTesting +import kotlin.math.abs object PhoneNumberUtil { private val noNumbersPattern = """^\D+$""".toRegex() @@ -140,6 +141,45 @@ object PhoneNumberUtil { .mapNotNull { it } .mapNotNull(::parsePhoneNumbers) .toList() + + fun searchablePhoneNumbers(phone1: String, phone2: String?): String = + getPhoneNumbers(listOf(phone1, phone2)) + .asSequence() + .map(ParsedPhoneNumber::parsedNumbers) + .flatten() + .filter(String::isNotBlank) + .map { + if (it.startsWith("1") && it.length == 11) { + it.substring(1) + } else { + it + } + } + .flatMap { + if (it.length == 10) { + listOf(it, it.substring(3)) + } else { + listOf(it) + } + } + .toList() + .sortedWith( + { a, b -> + if (a.length == 10) { + return@sortedWith -1 + } + if (b.length == 10) { + return@sortedWith 1 + } + val closestToTen = abs(a.length - 10) - abs(b.length - 10) + if (closestToTen <= 0) { + -1 + } else { + 1 + } + }, + ) + .joinToString(" ") } data class ParsedPhoneNumber( diff --git a/core/data/src/main/java/com/crisiscleanup/core/data/model/NetworkWorksite.kt b/core/data/src/main/java/com/crisiscleanup/core/data/model/NetworkWorksite.kt index 92265337..67bf4e08 100644 --- a/core/data/src/main/java/com/crisiscleanup/core/data/model/NetworkWorksite.kt +++ b/core/data/src/main/java/com/crisiscleanup/core/data/model/NetworkWorksite.kt @@ -1,5 +1,6 @@ package com.crisiscleanup.core.data.model +import com.crisiscleanup.core.common.PhoneNumberUtil.searchablePhoneNumbers import com.crisiscleanup.core.database.model.WorksiteEntities import com.crisiscleanup.core.database.model.WorksiteEntity import com.crisiscleanup.core.database.model.WorksiteFlagEntity @@ -37,6 +38,7 @@ fun NetworkWorksiteFull.asEntity() = WorksiteEntity( name = name, phone1 = phone1, phone2 = phone2, + phoneSearch = searchablePhoneNumbers(phone1, phone2), plusCode = plusCode, postalCode = postalCode ?: "", reportedBy = reportedBy, @@ -70,6 +72,7 @@ fun NetworkWorksiteCoreData.asEntity() = WorksiteEntity( name = name, phone1 = phone1, phone2 = phone2, + phoneSearch = searchablePhoneNumbers(phone1, phone2), plusCode = plusCode, postalCode = postalCode ?: "", reportedBy = reportedBy, @@ -106,6 +109,7 @@ fun NetworkWorksiteShort.asEntity() = WorksiteEntity( email = null, phone1 = null, phone2 = null, + phoneSearch = null, plusCode = null, reportedBy = null, what3Words = null, @@ -138,6 +142,7 @@ fun NetworkWorksitePage.asEntity() = WorksiteEntity( email = email, phone1 = phone1, phone2 = phone2, + phoneSearch = searchablePhoneNumbers(phone1, phone2), plusCode = plusCode, reportedBy = reportedBy, what3Words = what3words, diff --git a/core/database/schemas/com.crisiscleanup.core.database.CrisisCleanupDatabase/46.json b/core/database/schemas/com.crisiscleanup.core.database.CrisisCleanupDatabase/46.json new file mode 100644 index 00000000..a86f415b --- /dev/null +++ b/core/database/schemas/com.crisiscleanup.core.database.CrisisCleanupDatabase/46.json @@ -0,0 +1,3379 @@ +{ + "formatVersion": 1, + "database": { + "version": 46, + "identityHash": "bca6de9e826d883a435f11ffeb93f80a", + "entities": [ + { + "tableName": "work_type_statuses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`status` TEXT NOT NULL, `name` TEXT NOT NULL, `list_order` INTEGER NOT NULL, `primary_state` TEXT NOT NULL, PRIMARY KEY(`status`))", + "fields": [ + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "listOrder", + "columnName": "list_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "primaryState", + "columnName": "primary_state", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "status" + ] + }, + "indices": [ + { + "name": "index_work_type_statuses_list_order", + "unique": false, + "columnNames": [ + "list_order" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_work_type_statuses_list_order` ON `${TABLE_NAME}` (`list_order`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "incidents", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `start_at` INTEGER NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL DEFAULT '', `case_label` TEXT NOT NULL DEFAULT '', `incident_type` TEXT NOT NULL DEFAULT '', `active_phone_number` TEXT DEFAULT '', `turn_on_release` INTEGER NOT NULL DEFAULT 0, `is_archived` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "startAt", + "columnName": "start_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "caseLabel", + "columnName": "case_label", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "type", + "columnName": "incident_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "activePhoneNumber", + "columnName": "active_phone_number", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "turnOnRelease", + "columnName": "turn_on_release", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "isArchived", + "columnName": "is_archived", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "idx_newest_to_oldest_incidents", + "unique": false, + "columnNames": [ + "start_at" + ], + "orders": [ + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `idx_newest_to_oldest_incidents` ON `${TABLE_NAME}` (`start_at` DESC)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "incident_locations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `location` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "location", + "columnName": "location", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "incident_to_incident_location", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`incident_id` INTEGER NOT NULL, `incident_location_id` INTEGER NOT NULL, PRIMARY KEY(`incident_id`, `incident_location_id`), FOREIGN KEY(`incident_id`) REFERENCES `incidents`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`incident_location_id`) REFERENCES `incident_locations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "incidentLocationId", + "columnName": "incident_location_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "incident_id", + "incident_location_id" + ] + }, + "indices": [ + { + "name": "idx_incident_location_to_incident", + "unique": false, + "columnNames": [ + "incident_location_id", + "incident_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `idx_incident_location_to_incident` ON `${TABLE_NAME}` (`incident_location_id`, `incident_id`)" + } + ], + "foreignKeys": [ + { + "table": "incidents", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "incident_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "incident_locations", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "incident_location_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "incident_form_fields", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`incident_id` INTEGER NOT NULL, `label` TEXT NOT NULL, `html_type` TEXT NOT NULL, `data_group` TEXT NOT NULL, `help` TEXT DEFAULT '', `placeholder` TEXT DEFAULT '', `read_only_break_glass` INTEGER NOT NULL, `values_default_json` TEXT DEFAULT '', `is_checkbox_default_true` INTEGER DEFAULT 0, `order_label` INTEGER NOT NULL DEFAULT -1, `validation` TEXT DEFAULT '', `recur_default` TEXT DEFAULT '0', `values_json` TEXT DEFAULT '', `is_required` INTEGER DEFAULT 0, `is_read_only` INTEGER DEFAULT 0, `list_order` INTEGER NOT NULL, `is_invalidated` INTEGER NOT NULL, `field_key` TEXT NOT NULL, `field_parent_key` TEXT DEFAULT '', `parent_key` TEXT NOT NULL DEFAULT '', `selected_toggle_work_type` TEXT DEFAULT '', PRIMARY KEY(`incident_id`, `parent_key`, `field_key`), FOREIGN KEY(`incident_id`) REFERENCES `incidents`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "htmlType", + "columnName": "html_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dataGroup", + "columnName": "data_group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "help", + "columnName": "help", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "placeholder", + "columnName": "placeholder", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "readOnlyBreakGlass", + "columnName": "read_only_break_glass", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "valuesDefaultJson", + "columnName": "values_default_json", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "isCheckboxDefaultTrue", + "columnName": "is_checkbox_default_true", + "affinity": "INTEGER", + "notNull": false, + "defaultValue": "0" + }, + { + "fieldPath": "orderLabel", + "columnName": "order_label", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "validation", + "columnName": "validation", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "recurDefault", + "columnName": "recur_default", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "'0'" + }, + { + "fieldPath": "valuesJson", + "columnName": "values_json", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "isRequired", + "columnName": "is_required", + "affinity": "INTEGER", + "notNull": false, + "defaultValue": "0" + }, + { + "fieldPath": "isReadOnly", + "columnName": "is_read_only", + "affinity": "INTEGER", + "notNull": false, + "defaultValue": "0" + }, + { + "fieldPath": "listOrder", + "columnName": "list_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isInvalidated", + "columnName": "is_invalidated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fieldKey", + "columnName": "field_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fieldParentKey", + "columnName": "field_parent_key", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "parentKeyNonNull", + "columnName": "parent_key", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "selectToggleWorkType", + "columnName": "selected_toggle_work_type", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "incident_id", + "parent_key", + "field_key" + ] + }, + "indices": [ + { + "name": "index_incident_form_fields_data_group_parent_key_list_order", + "unique": false, + "columnNames": [ + "data_group", + "parent_key", + "list_order" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_incident_form_fields_data_group_parent_key_list_order` ON `${TABLE_NAME}` (`data_group`, `parent_key`, `list_order`)" + } + ], + "foreignKeys": [ + { + "table": "incidents", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "incident_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "locations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `shape_type` TEXT NOT NULL DEFAULT '', `coordinates` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shapeType", + "columnName": "shape_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "coordinates", + "columnName": "coordinates", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "worksite_sync_stats", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`incident_id` INTEGER NOT NULL, `sync_start` INTEGER NOT NULL DEFAULT 0, `target_count` INTEGER NOT NULL, `paged_count` INTEGER NOT NULL DEFAULT 0, `successful_sync` INTEGER, `attempted_sync` INTEGER, `attempted_counter` INTEGER NOT NULL, `app_build_version_code` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`incident_id`))", + "fields": [ + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "syncStart", + "columnName": "sync_start", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "targetCount", + "columnName": "target_count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pagedCount", + "columnName": "paged_count", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "successfulSync", + "columnName": "successful_sync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attemptedSync", + "columnName": "attempted_sync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attemptedCounter", + "columnName": "attempted_counter", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appBuildVersionCode", + "columnName": "app_build_version_code", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "incident_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "worksites_root", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `sync_uuid` TEXT NOT NULL DEFAULT '', `local_modified_at` INTEGER NOT NULL DEFAULT 0, `synced_at` INTEGER NOT NULL DEFAULT 0, `local_global_uuid` TEXT NOT NULL DEFAULT '', `is_local_modified` INTEGER NOT NULL DEFAULT 0, `sync_attempt` INTEGER NOT NULL DEFAULT 0, `network_id` INTEGER NOT NULL DEFAULT -1, `incident_id` INTEGER NOT NULL, FOREIGN KEY(`incident_id`) REFERENCES `incidents`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "syncUuid", + "columnName": "sync_uuid", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "localModifiedAt", + "columnName": "local_modified_at", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "syncedAt", + "columnName": "synced_at", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "localGlobalUuid", + "columnName": "local_global_uuid", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "isLocalModified", + "columnName": "is_local_modified", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "syncAttempt", + "columnName": "sync_attempt", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_worksites_root_network_id_local_global_uuid", + "unique": true, + "columnNames": [ + "network_id", + "local_global_uuid" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_worksites_root_network_id_local_global_uuid` ON `${TABLE_NAME}` (`network_id`, `local_global_uuid`)" + }, + { + "name": "index_worksites_root_incident_id_network_id", + "unique": false, + "columnNames": [ + "incident_id", + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_root_incident_id_network_id` ON `${TABLE_NAME}` (`incident_id`, `network_id`)" + }, + { + "name": "index_worksites_root_is_local_modified_local_modified_at", + "unique": false, + "columnNames": [ + "is_local_modified", + "local_modified_at" + ], + "orders": [ + "DESC", + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_root_is_local_modified_local_modified_at` ON `${TABLE_NAME}` (`is_local_modified` DESC, `local_modified_at` DESC)" + } + ], + "foreignKeys": [ + { + "table": "incidents", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "incident_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "worksites", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `network_id` INTEGER NOT NULL DEFAULT -1, `incident_id` INTEGER NOT NULL, `address` TEXT NOT NULL, `auto_contact_frequency_t` TEXT, `case_number` TEXT NOT NULL, `case_number_order` INTEGER NOT NULL DEFAULT 0, `city` TEXT NOT NULL, `county` TEXT NOT NULL, `created_at` INTEGER, `email` TEXT DEFAULT '', `favorite_id` INTEGER, `key_work_type_type` TEXT NOT NULL DEFAULT '', `key_work_type_org` INTEGER, `key_work_type_status` TEXT NOT NULL DEFAULT '', `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `name` TEXT NOT NULL, `phone1` TEXT, `phone2` TEXT DEFAULT '', `phone_search` TEXT DEFAULT '', `plus_code` TEXT DEFAULT '', `postal_code` TEXT NOT NULL, `reported_by` INTEGER, `state` TEXT NOT NULL, `svi` REAL, `what3Words` TEXT DEFAULT '', `updated_at` INTEGER NOT NULL, `network_photo_count` INTEGER DEFAULT 0, `is_local_favorite` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`), FOREIGN KEY(`id`) REFERENCES `worksites_root`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "autoContactFrequencyT", + "columnName": "auto_contact_frequency_t", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "caseNumber", + "columnName": "case_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "caseNumberOrder", + "columnName": "case_number_order", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "county", + "columnName": "county", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "favoriteId", + "columnName": "favorite_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "keyWorkTypeType", + "columnName": "key_work_type_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "keyWorkTypeOrgClaim", + "columnName": "key_work_type_org", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "keyWorkTypeStatus", + "columnName": "key_work_type_status", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "latitude", + "columnName": "latitude", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "longitude", + "columnName": "longitude", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phone1", + "columnName": "phone1", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "phone2", + "columnName": "phone2", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "phoneSearch", + "columnName": "phone_search", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "plusCode", + "columnName": "plus_code", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "postalCode", + "columnName": "postal_code", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reportedBy", + "columnName": "reported_by", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "svi", + "columnName": "svi", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "what3Words", + "columnName": "what3Words", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "photoCount", + "columnName": "network_photo_count", + "affinity": "INTEGER", + "notNull": false, + "defaultValue": "0" + }, + { + "fieldPath": "isLocalFavorite", + "columnName": "is_local_favorite", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_worksites_incident_id_network_id", + "unique": false, + "columnNames": [ + "incident_id", + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_network_id` ON `${TABLE_NAME}` (`incident_id`, `network_id`)" + }, + { + "name": "index_worksites_network_id", + "unique": false, + "columnNames": [ + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_network_id` ON `${TABLE_NAME}` (`network_id`)" + }, + { + "name": "index_worksites_incident_id_latitude_longitude", + "unique": false, + "columnNames": [ + "incident_id", + "latitude", + "longitude" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_latitude_longitude` ON `${TABLE_NAME}` (`incident_id`, `latitude`, `longitude`)" + }, + { + "name": "index_worksites_incident_id_longitude_latitude", + "unique": false, + "columnNames": [ + "incident_id", + "longitude", + "latitude" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_longitude_latitude` ON `${TABLE_NAME}` (`incident_id`, `longitude`, `latitude`)" + }, + { + "name": "index_worksites_incident_id_svi", + "unique": false, + "columnNames": [ + "incident_id", + "svi" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_svi` ON `${TABLE_NAME}` (`incident_id`, `svi`)" + }, + { + "name": "index_worksites_incident_id_updated_at", + "unique": false, + "columnNames": [ + "incident_id", + "updated_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_updated_at` ON `${TABLE_NAME}` (`incident_id`, `updated_at`)" + }, + { + "name": "index_worksites_incident_id_created_at", + "unique": false, + "columnNames": [ + "incident_id", + "created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_created_at` ON `${TABLE_NAME}` (`incident_id`, `created_at`)" + }, + { + "name": "index_worksites_incident_id_case_number", + "unique": false, + "columnNames": [ + "incident_id", + "case_number" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_case_number` ON `${TABLE_NAME}` (`incident_id`, `case_number`)" + }, + { + "name": "index_worksites_incident_id_case_number_order_case_number", + "unique": false, + "columnNames": [ + "incident_id", + "case_number_order", + "case_number" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_case_number_order_case_number` ON `${TABLE_NAME}` (`incident_id`, `case_number_order`, `case_number`)" + }, + { + "name": "index_worksites_incident_id_name_county_city_case_number_order_case_number", + "unique": false, + "columnNames": [ + "incident_id", + "name", + "county", + "city", + "case_number_order", + "case_number" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_name_county_city_case_number_order_case_number` ON `${TABLE_NAME}` (`incident_id`, `name`, `county`, `city`, `case_number_order`, `case_number`)" + }, + { + "name": "index_worksites_incident_id_city_name_case_number_order_case_number", + "unique": false, + "columnNames": [ + "incident_id", + "city", + "name", + "case_number_order", + "case_number" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_city_name_case_number_order_case_number` ON `${TABLE_NAME}` (`incident_id`, `city`, `name`, `case_number_order`, `case_number`)" + }, + { + "name": "index_worksites_incident_id_county_name_case_number_order_case_number", + "unique": false, + "columnNames": [ + "incident_id", + "county", + "name", + "case_number_order", + "case_number" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksites_incident_id_county_name_case_number_order_case_number` ON `${TABLE_NAME}` (`incident_id`, `county`, `name`, `case_number_order`, `case_number`)" + } + ], + "foreignKeys": [ + { + "table": "worksites_root", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "work_types", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `network_id` INTEGER NOT NULL DEFAULT -1, `worksite_id` INTEGER NOT NULL, `created_at` INTEGER, `claimed_by` INTEGER, `next_recur_at` INTEGER, `phase` INTEGER, `recur` TEXT, `status` TEXT NOT NULL, `work_type` TEXT NOT NULL, FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "orgClaim", + "columnName": "claimed_by", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "nextRecurAt", + "columnName": "next_recur_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "phase", + "columnName": "phase", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "recur", + "columnName": "recur", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "workType", + "columnName": "work_type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "unique_worksite_work_type", + "unique": true, + "columnNames": [ + "worksite_id", + "work_type" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `unique_worksite_work_type` ON `${TABLE_NAME}` (`worksite_id`, `work_type`)" + }, + { + "name": "index_work_types_worksite_id_network_id", + "unique": false, + "columnNames": [ + "worksite_id", + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_work_types_worksite_id_network_id` ON `${TABLE_NAME}` (`worksite_id`, `network_id`)" + }, + { + "name": "index_work_types_status_worksite_id", + "unique": false, + "columnNames": [ + "status", + "worksite_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_work_types_status_worksite_id` ON `${TABLE_NAME}` (`status`, `worksite_id`)" + }, + { + "name": "index_work_types_claimed_by_worksite_id", + "unique": false, + "columnNames": [ + "claimed_by", + "worksite_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_work_types_claimed_by_worksite_id` ON `${TABLE_NAME}` (`claimed_by`, `worksite_id`)" + }, + { + "name": "index_work_types_network_id", + "unique": false, + "columnNames": [ + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_work_types_network_id` ON `${TABLE_NAME}` (`network_id`)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "worksite_form_data", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`worksite_id` INTEGER NOT NULL, `field_key` TEXT NOT NULL, `is_bool_value` INTEGER NOT NULL, `value_string` TEXT NOT NULL, `value_bool` INTEGER NOT NULL, PRIMARY KEY(`worksite_id`, `field_key`), FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fieldKey", + "columnName": "field_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isBoolValue", + "columnName": "is_bool_value", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "valueString", + "columnName": "value_string", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "valueBool", + "columnName": "value_bool", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "worksite_id", + "field_key" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "worksite_flags", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `network_id` INTEGER NOT NULL DEFAULT -1, `worksite_id` INTEGER NOT NULL, `action` TEXT, `created_at` INTEGER NOT NULL, `is_high_priority` INTEGER DEFAULT 0, `notes` TEXT DEFAULT '', `reason_t` TEXT NOT NULL, `requested_action` TEXT DEFAULT '', FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "action", + "columnName": "action", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isHighPriority", + "columnName": "is_high_priority", + "affinity": "INTEGER", + "notNull": false, + "defaultValue": "0" + }, + { + "fieldPath": "notes", + "columnName": "notes", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "reasonT", + "columnName": "reason_t", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "requestedAction", + "columnName": "requested_action", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "unique_worksite_flag", + "unique": true, + "columnNames": [ + "worksite_id", + "reason_t" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `unique_worksite_flag` ON `${TABLE_NAME}` (`worksite_id`, `reason_t`)" + }, + { + "name": "index_worksite_flags_reason_t", + "unique": false, + "columnNames": [ + "reason_t" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksite_flags_reason_t` ON `${TABLE_NAME}` (`reason_t`)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "worksite_notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `local_global_uuid` TEXT NOT NULL DEFAULT '', `network_id` INTEGER NOT NULL DEFAULT -1, `worksite_id` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `is_survivor` INTEGER NOT NULL, `note` TEXT NOT NULL DEFAULT '', FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localGlobalUuid", + "columnName": "local_global_uuid", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isSurvivor", + "columnName": "is_survivor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "unique_worksite_note", + "unique": true, + "columnNames": [ + "worksite_id", + "network_id", + "local_global_uuid" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `unique_worksite_note` ON `${TABLE_NAME}` (`worksite_id`, `network_id`, `local_global_uuid`)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "language_translations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `translations_json` TEXT, `synced_at` INTEGER DEFAULT 0, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "translationsJson", + "columnName": "translations_json", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "syncedAt", + "columnName": "synced_at", + "affinity": "INTEGER", + "notNull": false, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "key" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sync_logs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `log_time` INTEGER NOT NULL, `log_type` TEXT NOT NULL DEFAULT '', `message` TEXT NOT NULL, `details` TEXT NOT NULL DEFAULT '')", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "logTime", + "columnName": "log_time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "logType", + "columnName": "log_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "details", + "columnName": "details", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_sync_logs_log_time", + "unique": false, + "columnNames": [ + "log_time" + ], + "orders": [ + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_sync_logs_log_time` ON `${TABLE_NAME}` (`log_time` DESC)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "worksite_changes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `app_version` INTEGER NOT NULL, `organization_id` INTEGER NOT NULL, `worksite_id` INTEGER NOT NULL, `sync_uuid` TEXT NOT NULL DEFAULT '', `change_model_version` INTEGER NOT NULL, `change_data` TEXT NOT NULL, `created_at` INTEGER NOT NULL, `save_attempt` INTEGER NOT NULL DEFAULT 0, `archive_action` TEXT NOT NULL, `save_attempt_at` INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(`worksite_id`) REFERENCES `worksites_root`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appVersion", + "columnName": "app_version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "organizationId", + "columnName": "organization_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "syncUuid", + "columnName": "sync_uuid", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "changeModelVersion", + "columnName": "change_model_version", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "changeData", + "columnName": "change_data", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "saveAttempt", + "columnName": "save_attempt", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "archiveAction", + "columnName": "archive_action", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "saveAttemptAt", + "columnName": "save_attempt_at", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_worksite_changes_worksite_id_created_at", + "unique": false, + "columnNames": [ + "worksite_id", + "created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksite_changes_worksite_id_created_at` ON `${TABLE_NAME}` (`worksite_id`, `created_at`)" + }, + { + "name": "index_worksite_changes_worksite_id_save_attempt", + "unique": false, + "columnNames": [ + "worksite_id", + "save_attempt" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksite_changes_worksite_id_save_attempt` ON `${TABLE_NAME}` (`worksite_id`, `save_attempt`)" + }, + { + "name": "index_worksite_changes_worksite_id_save_attempt_at_created_at", + "unique": false, + "columnNames": [ + "worksite_id", + "save_attempt_at", + "created_at" + ], + "orders": [ + "ASC", + "ASC", + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksite_changes_worksite_id_save_attempt_at_created_at` ON `${TABLE_NAME}` (`worksite_id` ASC, `save_attempt_at` ASC, `created_at` DESC)" + } + ], + "foreignKeys": [ + { + "table": "worksites_root", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "incident_organizations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `primary_location` INTEGER, `secondary_location` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "primaryLocation", + "columnName": "primary_location", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "secondaryLocation", + "columnName": "secondary_location", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "person_contacts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `first_name` TEXT NOT NULL, `last_name` TEXT NOT NULL, `email` TEXT NOT NULL, `mobile` TEXT NOT NULL, `profilePictureUri` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "first_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "last_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mobile", + "columnName": "mobile", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "profilePictureUri", + "columnName": "profilePictureUri", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "organization_to_primary_contact", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`organization_id` INTEGER NOT NULL, `contact_id` INTEGER NOT NULL, PRIMARY KEY(`organization_id`, `contact_id`), FOREIGN KEY(`organization_id`) REFERENCES `incident_organizations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`contact_id`) REFERENCES `person_contacts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "organizationId", + "columnName": "organization_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "contactId", + "columnName": "contact_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "organization_id", + "contact_id" + ] + }, + "indices": [ + { + "name": "idx_contact_to_organization", + "unique": false, + "columnNames": [ + "contact_id", + "organization_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `idx_contact_to_organization` ON `${TABLE_NAME}` (`contact_id`, `organization_id`)" + } + ], + "foreignKeys": [ + { + "table": "incident_organizations", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "organization_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "person_contacts", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "contact_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "organization_to_affiliate", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `affiliate_id` INTEGER NOT NULL, PRIMARY KEY(`id`, `affiliate_id`), FOREIGN KEY(`id`) REFERENCES `incident_organizations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "affiliateId", + "columnName": "affiliate_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "affiliate_id" + ] + }, + "indices": [ + { + "name": "index_organization_to_affiliate_affiliate_id_id", + "unique": false, + "columnNames": [ + "affiliate_id", + "id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_organization_to_affiliate_affiliate_id_id` ON `${TABLE_NAME}` (`affiliate_id`, `id`)" + } + ], + "foreignKeys": [ + { + "table": "incident_organizations", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "incident_organization_sync_stats", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`incident_id` INTEGER NOT NULL, `target_count` INTEGER NOT NULL, `successful_sync` INTEGER, `app_build_version_code` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`incident_id`))", + "fields": [ + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "targetCount", + "columnName": "target_count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "successfulSync", + "columnName": "successful_sync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "appBuildVersionCode", + "columnName": "app_build_version_code", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "incident_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "recent_worksites", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `incident_id` INTEGER NOT NULL, `viewed_at` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewedAt", + "columnName": "viewed_at", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_recent_worksites_incident_id_viewed_at", + "unique": false, + "columnNames": [ + "incident_id", + "viewed_at" + ], + "orders": [ + "ASC", + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_recent_worksites_incident_id_viewed_at` ON `${TABLE_NAME}` (`incident_id` ASC, `viewed_at` DESC)" + }, + { + "name": "index_recent_worksites_viewed_at", + "unique": false, + "columnNames": [ + "viewed_at" + ], + "orders": [ + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_recent_worksites_viewed_at` ON `${TABLE_NAME}` (`viewed_at` DESC)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "worksite_work_type_requests", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `network_id` INTEGER NOT NULL DEFAULT -1, `worksite_id` INTEGER NOT NULL, `work_type` TEXT NOT NULL, `reason` TEXT NOT NULL, `by_org` INTEGER NOT NULL, `to_org` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `approved_at` INTEGER, `rejected_at` INTEGER, `approved_rejected_reason` TEXT NOT NULL, FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "workType", + "columnName": "work_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reason", + "columnName": "reason", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "byOrg", + "columnName": "by_org", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "toOrg", + "columnName": "to_org", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "approvedAt", + "columnName": "approved_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "rejectedAt", + "columnName": "rejected_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "approvedRejectedReason", + "columnName": "approved_rejected_reason", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_worksite_work_type_requests_worksite_id_work_type_by_org", + "unique": true, + "columnNames": [ + "worksite_id", + "work_type", + "by_org" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_worksite_work_type_requests_worksite_id_work_type_by_org` ON `${TABLE_NAME}` (`worksite_id`, `work_type`, `by_org`)" + }, + { + "name": "index_worksite_work_type_requests_network_id", + "unique": false, + "columnNames": [ + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksite_work_type_requests_network_id` ON `${TABLE_NAME}` (`network_id`)" + }, + { + "name": "index_worksite_work_type_requests_worksite_id_by_org", + "unique": false, + "columnNames": [ + "worksite_id", + "by_org" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksite_work_type_requests_worksite_id_by_org` ON `${TABLE_NAME}` (`worksite_id`, `by_org`)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "network_files", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `file_id` INTEGER NOT NULL DEFAULT 0, `file_type_t` TEXT NOT NULL, `full_url` TEXT, `large_thumbnail_url` TEXT, `mime_content_type` TEXT NOT NULL, `small_thumbnail_url` TEXT, `tag` TEXT, `title` TEXT, `url` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "fileId", + "columnName": "file_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "fileTypeT", + "columnName": "file_type_t", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fullUrl", + "columnName": "full_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "largeThumbnailUrl", + "columnName": "large_thumbnail_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "mimeContentType", + "columnName": "mime_content_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "smallThumbnailUrl", + "columnName": "small_thumbnail_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "worksite_to_network_file", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`worksite_id` INTEGER NOT NULL, `network_file_id` INTEGER NOT NULL, PRIMARY KEY(`worksite_id`, `network_file_id`), FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`network_file_id`) REFERENCES `network_files`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "networkFileId", + "columnName": "network_file_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "worksite_id", + "network_file_id" + ] + }, + "indices": [ + { + "name": "index_worksite_to_network_file_network_file_id_worksite_id", + "unique": false, + "columnNames": [ + "network_file_id", + "worksite_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_worksite_to_network_file_network_file_id_worksite_id` ON `${TABLE_NAME}` (`network_file_id`, `worksite_id`)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "network_files", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "network_file_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "network_file_local_images", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `is_deleted` INTEGER NOT NULL, `rotate_degrees` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`id`) REFERENCES `network_files`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDeleted", + "columnName": "is_deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rotateDegrees", + "columnName": "rotate_degrees", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_network_file_local_images_is_deleted", + "unique": false, + "columnNames": [ + "is_deleted" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_network_file_local_images_is_deleted` ON `${TABLE_NAME}` (`is_deleted`)" + } + ], + "foreignKeys": [ + { + "table": "network_files", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "worksite_local_images", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `worksite_id` INTEGER NOT NULL, `local_document_id` TEXT NOT NULL, `uri` TEXT NOT NULL, `tag` TEXT NOT NULL, `rotate_degrees` INTEGER NOT NULL, FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "documentId", + "columnName": "local_document_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "uri", + "columnName": "uri", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rotateDegrees", + "columnName": "rotate_degrees", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_worksite_local_images_worksite_id_local_document_id", + "unique": true, + "columnNames": [ + "worksite_id", + "local_document_id" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_worksite_local_images_worksite_id_local_document_id` ON `${TABLE_NAME}` (`worksite_id`, `local_document_id`)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "incident_worksites_full_sync_stats", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`incident_id` INTEGER NOT NULL, `synced_at` INTEGER, `center_my_location` INTEGER NOT NULL, `center_latitude` REAL NOT NULL DEFAULT 999, `center_longitude` REAL NOT NULL DEFAULT 999, `query_area_radius` REAL NOT NULL, PRIMARY KEY(`incident_id`), FOREIGN KEY(`incident_id`) REFERENCES `worksite_sync_stats`(`incident_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "syncedAt", + "columnName": "synced_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isMyLocationCentered", + "columnName": "center_my_location", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latitude", + "columnName": "center_latitude", + "affinity": "REAL", + "notNull": true, + "defaultValue": "999" + }, + { + "fieldPath": "longitude", + "columnName": "center_longitude", + "affinity": "REAL", + "notNull": true, + "defaultValue": "999" + }, + { + "fieldPath": "radius", + "columnName": "query_area_radius", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "incident_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "worksite_sync_stats", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "incident_id" + ], + "referencedColumns": [ + "incident_id" + ] + } + ] + }, + { + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "simple", + "tokenizerArgs": [], + "contentTable": "incidents", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [ + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_fts_BEFORE_UPDATE BEFORE UPDATE ON `incidents` BEGIN DELETE FROM `incident_fts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_fts_BEFORE_DELETE BEFORE DELETE ON `incidents` BEGIN DELETE FROM `incident_fts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_fts_AFTER_UPDATE AFTER UPDATE ON `incidents` BEGIN INSERT INTO `incident_fts`(`docid`, `name`, `short_name`, `incident_type`) VALUES (NEW.`rowid`, NEW.`name`, NEW.`short_name`, NEW.`incident_type`); END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_fts_AFTER_INSERT AFTER INSERT ON `incidents` BEGIN INSERT INTO `incident_fts`(`docid`, `name`, `short_name`, `incident_type`) VALUES (NEW.`rowid`, NEW.`name`, NEW.`short_name`, NEW.`incident_type`); END" + ], + "tableName": "incident_fts", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`name` TEXT NOT NULL, `short_name` TEXT NOT NULL DEFAULT '', `incident_type` TEXT NOT NULL DEFAULT '', content=`incidents`)", + "fields": [ + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "type", + "columnName": "incident_type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "indices": [], + "foreignKeys": [] + }, + { + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "simple", + "tokenizerArgs": [], + "contentTable": "incident_organizations", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [ + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_organization_fts_BEFORE_UPDATE BEFORE UPDATE ON `incident_organizations` BEGIN DELETE FROM `incident_organization_fts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_organization_fts_BEFORE_DELETE BEFORE DELETE ON `incident_organizations` BEGIN DELETE FROM `incident_organization_fts` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_organization_fts_AFTER_UPDATE AFTER UPDATE ON `incident_organizations` BEGIN INSERT INTO `incident_organization_fts`(`docid`, `name`) VALUES (NEW.`rowid`, NEW.`name`); END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_incident_organization_fts_AFTER_INSERT AFTER INSERT ON `incident_organizations` BEGIN INSERT INTO `incident_organization_fts`(`docid`, `name`) VALUES (NEW.`rowid`, NEW.`name`); END" + ], + "tableName": "incident_organization_fts", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`name` TEXT NOT NULL, content=`incident_organizations`)", + "fields": [ + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "case_history_events", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `worksite_id` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `created_by` INTEGER NOT NULL, `event_key` TEXT NOT NULL, `past_tense_t` TEXT NOT NULL, `actor_location_name` TEXT NOT NULL, `recipient_location_name` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`worksite_id`) REFERENCES `worksites`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "worksiteId", + "columnName": "worksite_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdBy", + "columnName": "created_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "eventKey", + "columnName": "event_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pastTenseT", + "columnName": "past_tense_t", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "actorLocationName", + "columnName": "actor_location_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "recipientLocationName", + "columnName": "recipient_location_name", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_case_history_events_worksite_id_created_by_created_at", + "unique": false, + "columnNames": [ + "worksite_id", + "created_by", + "created_at" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_case_history_events_worksite_id_created_by_created_at` ON `${TABLE_NAME}` (`worksite_id`, `created_by`, `created_at`)" + } + ], + "foreignKeys": [ + { + "table": "worksites", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "worksite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "case_history_event_attrs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `incident_name` TEXT NOT NULL, `patient_case_number` TEXT, `patient_id` INTEGER NOT NULL, `patient_label_t` TEXT, `patient_location_name` TEXT, `patient_name_t` TEXT, `patient_reason_t` TEXT, `patient_status_name_t` TEXT, `recipient_case_number` TEXT, `recipient_id` INTEGER, `recipient_name` TEXT, `recipient_name_t` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`id`) REFERENCES `case_history_events`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "incidentName", + "columnName": "incident_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "patientCaseNumber", + "columnName": "patient_case_number", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "patientId", + "columnName": "patient_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "patientLabelT", + "columnName": "patient_label_t", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "patientLocationName", + "columnName": "patient_location_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "patientNameT", + "columnName": "patient_name_t", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "patientReasonT", + "columnName": "patient_reason_t", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "patientStatusNameT", + "columnName": "patient_status_name_t", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "recipientCaseNumber", + "columnName": "recipient_case_number", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "recipientId", + "columnName": "recipient_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "recipientName", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "recipientNameT", + "columnName": "recipient_name_t", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "case_history_events", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "person_to_organization", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `organization_id` INTEGER NOT NULL, PRIMARY KEY(`id`, `organization_id`), FOREIGN KEY(`id`) REFERENCES `person_contacts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`organization_id`) REFERENCES `incident_organizations`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "organizationId", + "columnName": "organization_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "organization_id" + ] + }, + "indices": [ + { + "name": "index_person_to_organization_organization_id_id", + "unique": false, + "columnNames": [ + "organization_id", + "id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_person_to_organization_organization_id_id` ON `${TABLE_NAME}` (`organization_id`, `id`)" + } + ], + "foreignKeys": [ + { + "table": "person_contacts", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "incident_organizations", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "organization_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "ftsVersion": "FTS4", + "ftsOptions": { + "tokenizer": "simple", + "tokenizerArgs": [], + "contentTable": "worksites", + "languageIdColumnName": "", + "matchInfo": "FTS4", + "notIndexedColumns": [], + "prefixSizes": [], + "preferredOrder": "ASC" + }, + "contentSyncTriggers": [ + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_worksite_text_fts_c_BEFORE_UPDATE BEFORE UPDATE ON `worksites` BEGIN DELETE FROM `worksite_text_fts_c` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_worksite_text_fts_c_BEFORE_DELETE BEFORE DELETE ON `worksites` BEGIN DELETE FROM `worksite_text_fts_c` WHERE `docid`=OLD.`rowid`; END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_worksite_text_fts_c_AFTER_UPDATE AFTER UPDATE ON `worksites` BEGIN INSERT INTO `worksite_text_fts_c`(`docid`, `address`, `case_number`, `city`, `county`, `email`, `name`, `phone_search`) VALUES (NEW.`rowid`, NEW.`address`, NEW.`case_number`, NEW.`city`, NEW.`county`, NEW.`email`, NEW.`name`, NEW.`phone_search`); END", + "CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_worksite_text_fts_c_AFTER_INSERT AFTER INSERT ON `worksites` BEGIN INSERT INTO `worksite_text_fts_c`(`docid`, `address`, `case_number`, `city`, `county`, `email`, `name`, `phone_search`) VALUES (NEW.`rowid`, NEW.`address`, NEW.`case_number`, NEW.`city`, NEW.`county`, NEW.`email`, NEW.`name`, NEW.`phone_search`); END" + ], + "tableName": "worksite_text_fts_c", + "createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`address` TEXT NOT NULL, `case_number` TEXT NOT NULL, `city` TEXT NOT NULL, `county` TEXT NOT NULL, `email` TEXT NOT NULL, `name` TEXT NOT NULL, `phone_search` TEXT NOT NULL DEFAULT '', content=`worksites`)", + "fields": [ + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "caseNumber", + "columnName": "case_number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "county", + "columnName": "county", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "phoneSearch", + "columnName": "phone_search", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "incident_worksites_secondary_sync_stats", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`incident_id` INTEGER NOT NULL, `sync_start` INTEGER NOT NULL DEFAULT 0, `target_count` INTEGER NOT NULL, `paged_count` INTEGER NOT NULL DEFAULT 0, `successful_sync` INTEGER, `attempted_sync` INTEGER, `attempted_counter` INTEGER NOT NULL, `app_build_version_code` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`incident_id`), FOREIGN KEY(`incident_id`) REFERENCES `worksite_sync_stats`(`incident_id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "syncStart", + "columnName": "sync_start", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "targetCount", + "columnName": "target_count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pagedCount", + "columnName": "paged_count", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "successfulSync", + "columnName": "successful_sync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attemptedSync", + "columnName": "attempted_sync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "attemptedCounter", + "columnName": "attempted_counter", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appBuildVersionCode", + "columnName": "app_build_version_code", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "incident_id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "worksite_sync_stats", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "incident_id" + ], + "referencedColumns": [ + "incident_id" + ] + } + ] + }, + { + "tableName": "lists", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `network_id` INTEGER NOT NULL DEFAULT -1, `local_global_uuid` TEXT NOT NULL DEFAULT '', `created_by` INTEGER, `updated_by` INTEGER, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, `parent` INTEGER, `name` TEXT NOT NULL, `description` TEXT, `list_order` INTEGER, `tags` TEXT, `model` TEXT NOT NULL, `object_ids` TEXT NOT NULL DEFAULT '', `shared` TEXT NOT NULL, `permissions` TEXT NOT NULL, `incident_id` INTEGER, FOREIGN KEY(`incident_id`) REFERENCES `incidents`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "localGlobalUuid", + "columnName": "local_global_uuid", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "createdBy", + "columnName": "created_by", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "updatedBy", + "columnName": "updated_by", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "listOrder", + "columnName": "list_order", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "model", + "columnName": "model", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "objectIds", + "columnName": "object_ids", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "shared", + "columnName": "shared", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_lists_network_id_local_global_uuid", + "unique": true, + "columnNames": [ + "network_id", + "local_global_uuid" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_lists_network_id_local_global_uuid` ON `${TABLE_NAME}` (`network_id`, `local_global_uuid`)" + }, + { + "name": "index_lists_incident_id_updated_at", + "unique": false, + "columnNames": [ + "incident_id", + "updated_at" + ], + "orders": [ + "DESC", + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_lists_incident_id_updated_at` ON `${TABLE_NAME}` (`incident_id` DESC, `updated_at` DESC)" + }, + { + "name": "index_lists_updated_at", + "unique": false, + "columnNames": [ + "updated_at" + ], + "orders": [ + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_lists_updated_at` ON `${TABLE_NAME}` (`updated_at` DESC)" + }, + { + "name": "index_lists_model_updated_at", + "unique": false, + "columnNames": [ + "model", + "updated_at" + ], + "orders": [ + "DESC", + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_lists_model_updated_at` ON `${TABLE_NAME}` (`model` DESC, `updated_at` DESC)" + }, + { + "name": "index_lists_parent_list_order", + "unique": false, + "columnNames": [ + "parent", + "list_order" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_lists_parent_list_order` ON `${TABLE_NAME}` (`parent`, `list_order`)" + } + ], + "foreignKeys": [ + { + "table": "incidents", + "onDelete": "NO ACTION", + "onUpdate": "NO ACTION", + "columns": [ + "incident_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "teams_root", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `local_modified_at` INTEGER NOT NULL DEFAULT 0, `synced_at` INTEGER NOT NULL DEFAULT 0, `local_global_uuid` TEXT NOT NULL DEFAULT '', `is_local_modified` INTEGER NOT NULL DEFAULT 0, `sync_attempt` INTEGER NOT NULL DEFAULT 0, `network_id` INTEGER NOT NULL DEFAULT -1, `incident_id` INTEGER NOT NULL, FOREIGN KEY(`incident_id`) REFERENCES `incidents`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localModifiedAt", + "columnName": "local_modified_at", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "syncedAt", + "columnName": "synced_at", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "localGlobalUuid", + "columnName": "local_global_uuid", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "isLocalModified", + "columnName": "is_local_modified", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "syncAttempt", + "columnName": "sync_attempt", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_teams_root_network_id_local_global_uuid", + "unique": true, + "columnNames": [ + "network_id", + "local_global_uuid" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_teams_root_network_id_local_global_uuid` ON `${TABLE_NAME}` (`network_id`, `local_global_uuid`)" + }, + { + "name": "index_teams_root_incident_id_network_id", + "unique": false, + "columnNames": [ + "incident_id", + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_teams_root_incident_id_network_id` ON `${TABLE_NAME}` (`incident_id`, `network_id`)" + }, + { + "name": "index_teams_root_is_local_modified_local_modified_at", + "unique": false, + "columnNames": [ + "is_local_modified", + "local_modified_at" + ], + "orders": [ + "DESC", + "DESC" + ], + "createSql": "CREATE INDEX IF NOT EXISTS `index_teams_root_is_local_modified_local_modified_at` ON `${TABLE_NAME}` (`is_local_modified` DESC, `local_modified_at` DESC)" + } + ], + "foreignKeys": [ + { + "table": "incidents", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "incident_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "teams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `network_id` INTEGER NOT NULL DEFAULT -1, `incident_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `notes` TEXT NOT NULL, `color` TEXT NOT NULL, `case_count` INTEGER NOT NULL, `case_complete_count` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`id`) REFERENCES `teams_root`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "networkId", + "columnName": "network_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "incidentId", + "columnName": "incident_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "notes", + "columnName": "notes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "caseCount", + "columnName": "case_count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "completeCount", + "columnName": "case_complete_count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_teams_incident_id_network_id", + "unique": false, + "columnNames": [ + "incident_id", + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_teams_incident_id_network_id` ON `${TABLE_NAME}` (`incident_id`, `network_id`)" + }, + { + "name": "index_teams_network_id", + "unique": false, + "columnNames": [ + "network_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_teams_network_id` ON `${TABLE_NAME}` (`network_id`)" + }, + { + "name": "index_teams_incident_id_name", + "unique": false, + "columnNames": [ + "incident_id", + "name" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_teams_incident_id_name` ON `${TABLE_NAME}` (`incident_id`, `name`)" + } + ], + "foreignKeys": [ + { + "table": "teams_root", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "team_to_primary_contact", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`team_id` INTEGER NOT NULL, `contact_id` INTEGER NOT NULL, PRIMARY KEY(`team_id`, `contact_id`), FOREIGN KEY(`team_id`) REFERENCES `teams`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`contact_id`) REFERENCES `person_contacts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "teamId", + "columnName": "team_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "contactId", + "columnName": "contact_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "team_id", + "contact_id" + ] + }, + "indices": [ + { + "name": "idx_contact_to_team", + "unique": false, + "columnNames": [ + "contact_id", + "team_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `idx_contact_to_team` ON `${TABLE_NAME}` (`contact_id`, `team_id`)" + } + ], + "foreignKeys": [ + { + "table": "teams", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "team_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "person_contacts", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "contact_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "incident_data_sync_parameters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `updated_before` INTEGER NOT NULL, `updated_after` INTEGER NOT NULL, `full_updated_before` INTEGER NOT NULL, `full_updated_after` INTEGER NOT NULL, `bounded_region` TEXT NOT NULL, `bounded_synced_at` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`id`) REFERENCES `incidents`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedBefore", + "columnName": "updated_before", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAfter", + "columnName": "updated_after", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "additionalUpdatedBefore", + "columnName": "full_updated_before", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "additionalUpdatedAfter", + "columnName": "full_updated_after", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "boundedRegion", + "columnName": "bounded_region", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "boundedSyncedAt", + "columnName": "bounded_synced_at", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [ + { + "table": "incidents", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "id" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "views": [], + "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, 'bca6de9e826d883a435f11ffeb93f80a')" + ] + } +} \ No newline at end of file diff --git a/core/database/src/androidTest/java/com/crisiscleanup/core/database/dao/WorksiteDaoTest.kt b/core/database/src/androidTest/java/com/crisiscleanup/core/database/dao/WorksiteDaoTest.kt index 97bb67b8..22d368b4 100644 --- a/core/database/src/androidTest/java/com/crisiscleanup/core/database/dao/WorksiteDaoTest.kt +++ b/core/database/src/androidTest/java/com/crisiscleanup/core/database/dao/WorksiteDaoTest.kt @@ -393,6 +393,7 @@ fun testWorksiteEntity( name = "", phone1 = "", phone2 = null, + phoneSearch = null, plusCode = null, postalCode = "", reportedBy = 0, @@ -430,6 +431,7 @@ fun testWorksiteFullEntity( name = "full worksite", phone1 = "345-414-7825", phone2 = "835-621-8938", + phoneSearch = null, plusCode = "code 123", postalCode = "83425", reportedBy = 7835, @@ -467,6 +469,7 @@ fun testWorksiteShortEntity( name = "short worksite", phone1 = null, phone2 = null, + phoneSearch = null, plusCode = null, postalCode = "83425-shrt", reportedBy = null, diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/CrisisCleanupDatabase.kt b/core/database/src/main/java/com/crisiscleanup/core/database/CrisisCleanupDatabase.kt index 9cfbd017..36093f0e 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/CrisisCleanupDatabase.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/CrisisCleanupDatabase.kt @@ -11,6 +11,7 @@ import com.crisiscleanup.core.database.DatabaseMigrations.Schema18To19 import com.crisiscleanup.core.database.DatabaseMigrations.Schema2To3 import com.crisiscleanup.core.database.DatabaseMigrations.Schema35To36 import com.crisiscleanup.core.database.DatabaseMigrations.Schema3to4 +import com.crisiscleanup.core.database.DatabaseMigrations.Schema45To46 import com.crisiscleanup.core.database.dao.CaseHistoryDao import com.crisiscleanup.core.database.dao.IncidentDao import com.crisiscleanup.core.database.dao.IncidentDataSyncParameterDao @@ -118,7 +119,7 @@ import com.crisiscleanup.core.database.util.InstantConverter TeamMemberCrossRef::class, IncidentDataSyncParametersEntity::class, ], - version = 45, + version = 46, autoMigrations = [ AutoMigration(from = 1, to = 2), AutoMigration(from = 2, to = 3, spec = Schema2To3::class), @@ -164,6 +165,7 @@ import com.crisiscleanup.core.database.util.InstantConverter AutoMigration(from = 42, to = 43), AutoMigration(from = 43, to = 44), AutoMigration(from = 44, to = 45), + AutoMigration(from = 45, to = 46, spec = Schema45To46::class), ], exportSchema = true, ) diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/DatabaseMigrations.kt b/core/database/src/main/java/com/crisiscleanup/core/database/DatabaseMigrations.kt index f49cbea5..3056b343 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/DatabaseMigrations.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/DatabaseMigrations.kt @@ -60,4 +60,11 @@ object DatabaseMigrations { ), ) class Schema35To36 : AutoMigrationSpec + + @DeleteTable.Entries( + DeleteTable( + tableName = "worksite_text_fts_b", + ), + ) + class Schema45To46 : AutoMigrationSpec } diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDao.kt b/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDao.kt index 02c26ec3..b042b070 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDao.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDao.kt @@ -238,6 +238,7 @@ interface WorksiteDao { name =:name, phone1 =COALESCE(:phone1, phone1), phone2 =COALESCE(:phone2, phone2), + phone_search =COALESCE(:phoneSearch, phone_search), plus_code =COALESCE(:plusCode, plus_code), postal_code =:postalCode, reported_by =COALESCE(:reportedBy, reported_by), @@ -270,6 +271,7 @@ interface WorksiteDao { name: String, phone1: String?, phone2: String?, + phoneSearch: String?, plusCode: String?, postalCode: String, reportedBy: Long?, @@ -613,7 +615,7 @@ interface WorksiteDao { fun getRandomWorksiteCaseNumber(): String? @Transaction - @Query("INSERT INTO worksite_text_fts_b(worksite_text_fts_b) VALUES ('rebuild')") + @Query("INSERT INTO worksite_text_fts_c(worksite_text_fts_c) VALUES ('rebuild')") fun rebuildWorksiteTextFts() // TODO Is it possible to filter by incident_id with FTS match more efficiently? @@ -621,10 +623,10 @@ interface WorksiteDao { @Query( """ SELECT w.*, - matchinfo(worksite_text_fts_b, 'pcnalx') AS match_info - FROM worksite_text_fts_b f + matchinfo(worksite_text_fts_c, 'pcnalx') AS match_info + FROM worksite_text_fts_c f INNER JOIN worksites w ON f.docid=w.id - WHERE worksite_text_fts_b MATCH :query + WHERE worksite_text_fts_c MATCH :query LIMIT :limit """, ) @@ -637,9 +639,9 @@ interface WorksiteDao { @Query( """ SELECT w.id - FROM worksite_text_fts_b f + FROM worksite_text_fts_c f INNER JOIN worksites w ON f.docid=w.id - WHERE worksite_text_fts_b MATCH :query + WHERE worksite_text_fts_c MATCH :query LIMIT 1 """, ) diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDaoPlus.kt b/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDaoPlus.kt index 69173a0d..776ee6a2 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDaoPlus.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/dao/WorksiteDaoPlus.kt @@ -196,6 +196,7 @@ class WorksiteDaoPlus @Inject constructor( name = name, phone1 = phone1, phone2 = phone2, + phoneSearch = phoneSearch, plusCode = plusCode, postalCode = postalCode, reportedBy = reportedBy, diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt b/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt index f02151ad..725aed00 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt @@ -18,7 +18,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.ensureActive @Entity( - "worksite_text_fts_b", + "worksite_text_fts_c", ) @Fts4(contentEntity = WorksiteEntity::class) data class WorksiteTextFtsEntity( @@ -29,8 +29,8 @@ data class WorksiteTextFtsEntity( val county: String, val email: String, val name: String, - val phone1: String, - val phone2: String, + @ColumnInfo("phone_search", defaultValue = "") + val phoneSearch: String, ) data class PopulatedWorksiteTextMatchInfo( @@ -50,8 +50,7 @@ data class PopulatedWorksiteTextMatchInfo( matchInfoInts.okapiBm25Score(3) * 0.7 + matchInfoInts.okapiBm25Score(4) * 0.7 + matchInfoInts.okapiBm25Score(5) * 0.9 + - matchInfoInts.okapiBm25Score(6) * 0.6 + - matchInfoInts.okapiBm25Score(7) * 0.6 + matchInfoInts.okapiBm25Score(8) * 0.6 } override fun equals(other: Any?): Boolean { diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/model/Worksite.kt b/core/database/src/main/java/com/crisiscleanup/core/database/model/Worksite.kt index 161fbb70..26eef266 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/model/Worksite.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/model/Worksite.kt @@ -1,5 +1,6 @@ package com.crisiscleanup.core.database.model +import com.crisiscleanup.core.common.PhoneNumberUtil.searchablePhoneNumbers import com.crisiscleanup.core.common.UuidGenerator import com.crisiscleanup.core.model.data.WorkType import com.crisiscleanup.core.model.data.Worksite @@ -35,6 +36,7 @@ fun Worksite.asEntities( name = name, phone1 = phone1, phone2 = phone2, + phoneSearch = searchablePhoneNumbers(phone1, phone2), plusCode = plusCode, postalCode = postalCode, reportedBy = reportedBy, diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/model/WorksiteEntity.kt b/core/database/src/main/java/com/crisiscleanup/core/database/model/WorksiteEntity.kt index 677b94c4..4365c82c 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/model/WorksiteEntity.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/model/WorksiteEntity.kt @@ -13,7 +13,7 @@ import com.crisiscleanup.core.model.data.WorksiteFlag import com.crisiscleanup.core.model.data.WorksiteNote import kotlinx.datetime.Instant -// Changes below should update WorksitesStableModelBuildVersion in core.network +// Changes below should update WORKSITES_STABLE_MODEL_BUILD_VERSION in core.network @Entity( "worksites_root", @@ -119,6 +119,8 @@ data class WorksiteEntity( val phone1: String?, @ColumnInfo(defaultValue = "") val phone2: String?, + @ColumnInfo("phone_search", defaultValue = "") + val phoneSearch: String?, @ColumnInfo("plus_code", defaultValue = "") val plusCode: String?, @ColumnInfo("postal_code") diff --git a/core/model/src/main/java/com/crisiscleanup/core/model/data/IncidentDataSyncStats.kt b/core/model/src/main/java/com/crisiscleanup/core/model/data/IncidentDataSyncStats.kt index 8f4753b0..8d905c0e 100644 --- a/core/model/src/main/java/com/crisiscleanup/core/model/data/IncidentDataSyncStats.kt +++ b/core/model/src/main/java/com/crisiscleanup/core/model/data/IncidentDataSyncStats.kt @@ -5,7 +5,7 @@ import kotlinx.datetime.Instant /** * Build version of the app where worksite (related) entity models were last changed */ -private const val WORKSITES_STABLE_MODEL_BUILD_VERSION = 193 +private const val WORKSITES_STABLE_MODEL_BUILD_VERSION = 254 /** * Build version of the app where incident organization (related) entity models were last changed From 3ff3522c01a3bb789e38f2eaf868bbcf65653d91 Mon Sep 17 00:00:00 2001 From: hue Date: Thu, 10 Jul 2025 15:45:26 -0400 Subject: [PATCH 5/6] Fix Worksite FTS result scoring --- .../com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt b/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt index 725aed00..b01293cc 100644 --- a/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt +++ b/core/database/src/main/java/com/crisiscleanup/core/database/dao/fts/WorksiteTextFts.kt @@ -50,7 +50,7 @@ data class PopulatedWorksiteTextMatchInfo( matchInfoInts.okapiBm25Score(3) * 0.7 + matchInfoInts.okapiBm25Score(4) * 0.7 + matchInfoInts.okapiBm25Score(5) * 0.9 + - matchInfoInts.okapiBm25Score(8) * 0.6 + matchInfoInts.okapiBm25Score(6) * 0.6 } override fun equals(other: Any?): Boolean { From f13b7e3bf4c41511187767076383a5ed0d9f3c44 Mon Sep 17 00:00:00 2001 From: hue Date: Thu, 10 Jul 2025 16:07:29 -0400 Subject: [PATCH 6/6] Add description for action when otherwise blank --- .../crisiscleanup/feature/caseeditor/ui/ViewCaseScreen.kt | 6 +++++- .../java/com/crisiscleanup/feature/cases/ui/CasesScreen.kt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/feature/caseeditor/src/main/java/com/crisiscleanup/feature/caseeditor/ui/ViewCaseScreen.kt b/feature/caseeditor/src/main/java/com/crisiscleanup/feature/caseeditor/ui/ViewCaseScreen.kt index bf3c0c65..73e05b09 100644 --- a/feature/caseeditor/src/main/java/com/crisiscleanup/feature/caseeditor/ui/ViewCaseScreen.kt +++ b/feature/caseeditor/src/main/java/com/crisiscleanup/feature/caseeditor/ui/ViewCaseScreen.kt @@ -787,14 +787,18 @@ private fun LazyListScope.propertyInfoItems( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = listItemSpacedBy, ) { + val actionDescription = + LocalAppTranslator.current.translate("actions.jump_to_case") Image( modifier = Modifier.size(24.dp), painter = painterResource(R.drawable.ic_jump_to_case_on_map), - contentDescription = LocalAppTranslator.current.translate("actions.jump_to_case"), + contentDescription = actionDescription, ) if (distanceAwayText.isNotBlank()) { Text(distanceAwayText, style = MaterialTheme.typography.bodyLarge) + } else if (actionDescription?.isNotBlank() == true) { + Text(actionDescription, style = MaterialTheme.typography.bodyLarge) } } diff --git a/feature/cases/src/main/java/com/crisiscleanup/feature/cases/ui/CasesScreen.kt b/feature/cases/src/main/java/com/crisiscleanup/feature/cases/ui/CasesScreen.kt index 529998dd..2bedb74a 100644 --- a/feature/cases/src/main/java/com/crisiscleanup/feature/cases/ui/CasesScreen.kt +++ b/feature/cases/src/main/java/com/crisiscleanup/feature/cases/ui/CasesScreen.kt @@ -483,7 +483,7 @@ internal fun BoxScope.CasesMapView( onMarkerSelect: (WorksiteMapMark) -> Boolean = { false }, editedWorksiteLocation: LatLng? = null, isMyLocationEnabled: Boolean = false, - onEditLocationZoom: Float = 12f, + onEditLocationZoom: Float = 15f, isSatelliteMapType: Boolean = false, ) { // TODO Profile and optimize recompositions when map is changed (by user) if possible.