package loopdb import ( "errors" "fmt" "github.com/jackc/pgconn" "github.com/jackc/pgerrcode" "modernc.org/sqlite" sqlite3 "modernc.org/sqlite/lib" ) // MapSQLError attempts to interpret a given error as a database agnostic SQL // error. func MapSQLError(err error) error { // Attempt to interpret the error as a sqlite error. var sqliteErr *sqlite.Error if errors.As(err, &sqliteErr) { return parseSqliteError(sqliteErr) } // Attempt to interpret the error as a postgres error. var pqErr *pgconn.PgError if errors.As(err, &pqErr) { return parsePostgresError(pqErr) } // Return original error if it could not be classified as a database // specific error. return err } // parsePostgresError attempts to parse a sqlite error as a database agnostic // SQL error. func parseSqliteError(sqliteErr *sqlite.Error) error { switch sqliteErr.Code() { // Handle unique constraint violation error. case sqlite3.SQLITE_CONSTRAINT_UNIQUE: return &ErrSqlUniqueConstraintViolation{ DbError: sqliteErr, } default: return fmt.Errorf("unknown sqlite error: %w", sqliteErr) } } // parsePostgresError attempts to parse a postgres error as a database agnostic // SQL error. func parsePostgresError(pqErr *pgconn.PgError) error { switch pqErr.Code { // Handle unique constraint violation error. case pgerrcode.UniqueViolation: return &ErrSqlUniqueConstraintViolation{ DbError: pqErr, } default: return fmt.Errorf("unknown postgres error: %w", pqErr) } } // ErrSqlUniqueConstraintViolation is an error type which represents a database // agnostic SQL unique constraint violation. type ErrSqlUniqueConstraintViolation struct { DbError error } func (e ErrSqlUniqueConstraintViolation) Error() string { return fmt.Sprintf("sql unique constraint violation: %v", e.DbError) }