Skip to content

Instantly share code, notes, and snippets.

@glureau
Created February 20, 2023 15:39
Show Gist options
  • Save glureau/985e5f9287049e70621efd7cd7f6ef88 to your computer and use it in GitHub Desktop.
Save glureau/985e5f9287049e70621efd7cd7f6ef88 to your computer and use it in GitHub Desktop.
SQLDelight: deal with platform exceptions from commonMain
import android.database.sqlite.SQLiteAbortException
import android.database.sqlite.SQLiteAccessPermException
import android.database.sqlite.SQLiteBindOrColumnIndexOutOfRangeException
import android.database.sqlite.SQLiteBlobTooBigException
import android.database.sqlite.SQLiteCantOpenDatabaseException
import android.database.sqlite.SQLiteConstraintException
import android.database.sqlite.SQLiteDatabaseCorruptException
import android.database.sqlite.SQLiteDatabaseLockedException
import android.database.sqlite.SQLiteDatatypeMismatchException
import android.database.sqlite.SQLiteDiskIOException
import android.database.sqlite.SQLiteDoneException
import android.database.sqlite.SQLiteFullException
import android.database.sqlite.SQLiteMisuseException
import android.database.sqlite.SQLiteOutOfMemoryException
import android.database.sqlite.SQLiteReadOnlyDatabaseException
import android.database.sqlite.SQLiteTableLockedException
public actual val sqliteExceptionMapper: SqliteExceptionMapper = AndroidSqliteExceptionMapper()
private class AndroidSqliteExceptionMapper : SqliteExceptionMapper {
@Suppress("CyclomaticComplexMethod")
override fun map(t: Throwable): SqliteException {
val opResult = when (t) {
is SQLiteAbortException -> SqliteOperationResult.ABORT
is SQLiteAccessPermException -> SqliteOperationResult.PERM
is SQLiteBindOrColumnIndexOutOfRangeException -> SqliteOperationResult.RANGE
is SQLiteBlobTooBigException -> SqliteOperationResult.TOO_BIG
is SQLiteCantOpenDatabaseException -> SqliteOperationResult.CANT_OPEN
is SQLiteConstraintException -> SqliteOperationResult.CONSTRAINT
is SQLiteDatabaseCorruptException -> SqliteOperationResult.CORRUPT
is SQLiteDatabaseLockedException -> SqliteOperationResult.BUSY
is SQLiteDatatypeMismatchException -> SqliteOperationResult.MISMATCH
is SQLiteDiskIOException -> SqliteOperationResult.DISK
is SQLiteDoneException -> SqliteOperationResult.DONE
is SQLiteFullException -> SqliteOperationResult.FULL
is SQLiteMisuseException -> SqliteOperationResult.MISUSE
is SQLiteOutOfMemoryException -> SqliteOperationResult.NOMEM
is SQLiteReadOnlyDatabaseException -> SqliteOperationResult.READONLY
is SQLiteTableLockedException -> SqliteOperationResult.LOCKED
else -> SqliteOperationResult.UNKNOWN
}
return SqliteException(opResult, t)
}
}
public interface SqliteExceptionMapper {
public fun map(t: Throwable): SqliteException
}
public expect val sqliteExceptionMapper: SqliteExceptionMapper
// For iOS: https://github.com/touchlab/SQLiter/blob/main/sqliter-driver/src/nativeCommonMain/kotlin/co/touchlab/sqliter/interop/SQLiteException.kt
// For Android, using directly the specific android exceptions.
// Current strategy: use what's available on both platforms, if not available for iOS AND Android, then it's an UNKNOWN
public enum class SqliteOperationResult {
UNKNOWN,
PERM,
ABORT,
BUSY,
MISUSE,
TOO_BIG,
CANT_OPEN,
CONSTRAINT,
CORRUPT,
RANGE,
MISMATCH,
DISK,
DONE,
FULL,
NOMEM,
READONLY,
LOCKED,
}
public class SqliteException(
public val opResult: SqliteOperationResult,
cause: Throwable,
) : IllegalStateException(cause)
import co.touchlab.sqliter.interop.SQLiteExceptionErrorCode
import co.touchlab.sqliter.interop.SqliteErrorType
public actual val sqliteExceptionMapper: SqliteExceptionMapper = NativeSqliteExceptionMapper()
private class NativeSqliteExceptionMapper : SqliteExceptionMapper {
@Suppress("CyclomaticComplexMethod")
override fun map(t: Throwable): SqliteException {
val opResult = when {
t is SQLiteExceptionErrorCode -> when (t.errorType) {
// Not sure what an exception with OK means...
SqliteErrorType.SQLITE_OK -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_ERROR -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_INTERNAL -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_PERM -> SqliteOperationResult.PERM
SqliteErrorType.SQLITE_ABORT -> SqliteOperationResult.ABORT
SqliteErrorType.SQLITE_BUSY -> SqliteOperationResult.BUSY
SqliteErrorType.SQLITE_LOCKED -> SqliteOperationResult.LOCKED
SqliteErrorType.SQLITE_NOMEM -> SqliteOperationResult.NOMEM
SqliteErrorType.SQLITE_READONLY -> SqliteOperationResult.READONLY
SqliteErrorType.SQLITE_INTERRUPT -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_IOERR -> SqliteOperationResult.DISK
SqliteErrorType.SQLITE_CORRUPT -> SqliteOperationResult.CORRUPT
SqliteErrorType.SQLITE_NOTFOUND -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_FULL -> SqliteOperationResult.FULL
SqliteErrorType.SQLITE_CANTOPEN -> SqliteOperationResult.CANT_OPEN
SqliteErrorType.SQLITE_PROTOCOL -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_EMPTY -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_SCHEMA -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_TOOBIG -> SqliteOperationResult.TOO_BIG
SqliteErrorType.SQLITE_CONSTRAINT -> SqliteOperationResult.CONSTRAINT
SqliteErrorType.SQLITE_MISMATCH -> SqliteOperationResult.MISMATCH
SqliteErrorType.SQLITE_MISUSE -> SqliteOperationResult.MISUSE
SqliteErrorType.SQLITE_NOLFS -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_AUTH -> SqliteOperationResult.PERM // Almost...
SqliteErrorType.SQLITE_FORMAT -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_RANGE -> SqliteOperationResult.RANGE
SqliteErrorType.SQLITE_NOTADB -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_NOTICE -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_WARNING -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_ROW -> SqliteOperationResult.UNKNOWN
SqliteErrorType.SQLITE_DONE -> SqliteOperationResult.DONE
}
else -> SqliteOperationResult.UNKNOWN
}
return SqliteException(opResult, t)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment