Skip to content

Commit 2a2c83d

Browse files
authored
Limit the default amount of migration FK violations reported to 100 (#113)
1 parent 17a2480 commit 2a2c83d

File tree

9 files changed

+710
-32
lines changed

9 files changed

+710
-32
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ any violations, an `AndroidxSqliteDriver.ForeignKeyConstraintCheckException` is
9999
specific constraints that have been violated. This helps catch any inconsistencies in your data that might
100100
have been introduced during the migration.
101101

102+
> [!IMPORTANT]
103+
> By default, the first 100 violations will be parsed out of the result set of
104+
> `PRAGMA foreign_key_check` and stored in the `AndroidxSqliteDriver.ForeignKeyConstraintCheckException`.
105+
> If your use can result in a large number of violations you can adjust the max amount that will be processed via
106+
> `AndroidxSqliteConfiguration.maxMigrationForeignKeyConstraintViolationsToReport`.
107+
102108
## Connection Pooling
103109

104110
By default, one connection will be used for both reading and writing, and only one thread can acquire that connection

library/src/androidUnitTest/kotlin/com/eygraber/sqldelight/androidx/driver/AndroidxSqliteCommonTests.android.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ actual class CommonCallbackTest : AndroidxSqliteCallbackTest()
2020
@RunWith(RobolectricTestRunner::class)
2121
actual class CommonConcurrencyTest : AndroidxSqliteConcurrencyTest()
2222

23+
@RunWith(RobolectricTestRunner::class)
24+
actual class CommonCreationTest : AndroidxSqliteCreationTest()
25+
2326
@RunWith(RobolectricTestRunner::class)
2427
class AndroidGetDatabasePathConcurrencyTest : AndroidxSqliteConcurrencyTest() {
2528
override fun createDatabaseType(fullDbName: String): AndroidxSqliteDatabaseType.FileProvider {
@@ -45,7 +48,7 @@ actual class CommonDriverOpenFlagsTest : AndroidxSqliteDriverOpenFlagsTest()
4548
actual class CommonEphemeralTest : AndroidxSqliteEphemeralTest()
4649

4750
@RunWith(RobolectricTestRunner::class)
48-
actual class CommonMigrationKeyTest : AndroidxSqliteMigrationKeyTest()
51+
actual class CommonMigrationTest : AndroidxSqliteMigrationTest()
4952

5053
@RunWith(RobolectricTestRunner::class)
5154
actual class CommonQueryTest : AndroidxSqliteQueryTest()

library/src/commonMain/kotlin/com/eygraber/sqldelight/androidx/driver/AndroidxSqliteConfiguration.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ public class AndroidxSqliteConfiguration(
8181
SqliteJournalMode.WAL -> 4
8282
else -> 0
8383
},
84+
/**
85+
* The maximum number of foreign key constraint violations to report when
86+
* [isForeignKeyConstraintsCheckedAfterCreateOrUpdate] is `true` and `PRAGMA foreign_key_check` fails.
87+
*
88+
* Defaults to 100.
89+
*/
90+
public val maxMigrationForeignKeyConstraintViolationsToReport: Int = 100,
8491
) {
8592
public fun copy(
8693
isForeignKeyConstraintsEnabled: Boolean = this.isForeignKeyConstraintsEnabled,
@@ -94,5 +101,6 @@ public class AndroidxSqliteConfiguration(
94101
journalMode = journalMode,
95102
sync = sync,
96103
readerConnectionsCount = readerConnectionsCount,
104+
maxMigrationForeignKeyConstraintViolationsToReport = maxMigrationForeignKeyConstraintViolationsToReport,
97105
)
98106
}

library/src/commonMain/kotlin/com/eygraber/sqldelight/androidx/driver/AndroidxSqliteDriver.kt

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,26 @@ public class AndroidxSqliteDriver(
9292
migrationCallbacks = migrationCallbacks,
9393
)
9494

95-
public class ForeignKeyConstraintCheckException(message: String) : Exception(message)
95+
public data class ForeignKeyConstraintViolation(
96+
val referencingTable: String,
97+
val referencingRowId: Int,
98+
val referencedTable: String,
99+
val referencingConstraintIndex: Int,
100+
) {
101+
override fun toString(): String =
102+
"""
103+
|ForeignKeyConstraintViolation:
104+
| Constraint index: $referencingConstraintIndex
105+
| Referencing table: $referencingTable
106+
| Referencing rowId: $referencingRowId
107+
| Referenced table: $referencedTable
108+
""".trimMargin()
109+
}
110+
111+
public class ForeignKeyConstraintCheckException(
112+
public val violations: List<ForeignKeyConstraintViolation>,
113+
message: String,
114+
) : Exception(message)
96115

97116
@Suppress("NonBooleanPropertyPrefixedWithIs")
98117
private val isFirstInteraction = atomic(true)
@@ -471,29 +490,29 @@ private inline fun SQLiteConnection.withDeferredForeignKeyChecks(
471490

472491
if(configuration.isForeignKeyConstraintsCheckedAfterCreateOrUpdate) {
473492
prepare("PRAGMA foreign_key_check;").use { check ->
474-
val violations = mutableListOf<String>()
475-
while(check.step()) {
476-
val referencingTable = check.getText(0)
477-
val referencingRowId = check.getInt(1)
478-
val referencedTable = check.getText(2)
479-
val referencingConstraintIndex = check.getInt(3)
480-
493+
val violations = mutableListOf<AndroidxSqliteDriver.ForeignKeyConstraintViolation>()
494+
var count = 0
495+
while(check.step() && count++ < configuration.maxMigrationForeignKeyConstraintViolationsToReport) {
481496
violations.add(
482-
"""
483-
|Constraint index: $referencingConstraintIndex
484-
|Referencing table: $referencingTable
485-
|Referencing rowId: $referencingRowId
486-
|Referenced table: $referencedTable
487-
""".trimMargin(),
497+
AndroidxSqliteDriver.ForeignKeyConstraintViolation(
498+
referencingTable = check.getText(0),
499+
referencingRowId = check.getInt(1),
500+
referencedTable = check.getText(2),
501+
referencingConstraintIndex = check.getInt(3),
502+
),
488503
)
489504
}
490505

491506
if(violations.isNotEmpty()) {
507+
val unprintedViolationsCount = violations.size - 5
508+
val unprintedDisclaimer = if(unprintedViolationsCount > 0) " ($unprintedViolationsCount not shown)" else ""
509+
492510
throw AndroidxSqliteDriver.ForeignKeyConstraintCheckException(
493-
"""
494-
|The following foreign key constraints are violated:
511+
violations = violations,
512+
message = """
513+
|The following foreign key constraints are violated$unprintedDisclaimer:
495514
|
496-
|${violations.joinToString(separator = "\n\n")}
515+
|${violations.take(5).joinToString(separator = "\n\n")}
497516
""".trimMargin(),
498517
)
499518
}

library/src/commonTest/kotlin/com/eygraber/sqldelight/androidx/driver/AndroidxSqliteCommonTests.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import kotlinx.coroutines.CoroutineDispatcher
77

88
expect class CommonCallbackTest() : AndroidxSqliteCallbackTest
99
expect class CommonConcurrencyTest() : AndroidxSqliteConcurrencyTest
10+
expect class CommonCreationTest() : AndroidxSqliteCreationTest
1011
expect class CommonDriverTest() : AndroidxSqliteDriverTest
1112
expect class CommonDriverOpenFlagsTest() : AndroidxSqliteDriverOpenFlagsTest
1213
expect class CommonEphemeralTest() : AndroidxSqliteEphemeralTest
13-
expect class CommonMigrationKeyTest() : AndroidxSqliteMigrationKeyTest
14+
expect class CommonMigrationTest() : AndroidxSqliteMigrationTest
1415
expect class CommonQueryTest() : AndroidxSqliteQueryTest
1516
expect class CommonTransacterTest() : AndroidxSqliteTransacterTest
1617

0 commit comments

Comments
 (0)