package sqlite import ( "database/sql" "errors" "code.nochebuena.dev/einherjar/core/xerrors" ) // coder is the duck-type interface for SQLite extended error codes. // modernc.org/sqlite errors implement this interface. type coder interface{ Code() int } const ( sqliteConstraintPrimaryKey = 1555 sqliteConstraintUnique = 2067 sqliteConstraintForeignKey = 787 ) // HandleError maps database/sql and SQLite errors to typed [xerrors] values. // Returns nil when err is nil. Also available as [Provider.HandleError]. // // Mapped codes: // - sql.ErrNoRows → ErrNotFound // - SQLITE_CONSTRAINT_UNIQUE (2067) → ErrAlreadyExists // - SQLITE_CONSTRAINT_PRIMARYKEY (1555)→ ErrAlreadyExists // - SQLITE_CONSTRAINT_FOREIGNKEY (787) → ErrInvalidInput // - all others → ErrInternal func HandleError(err error) error { if err == nil { return nil } if errors.Is(err, sql.ErrNoRows) { return xerrors.New(xerrors.ErrNotFound, "record not found").WithError(err) } var ce coder if errors.As(err, &ce) { switch ce.Code() { case sqliteConstraintUnique, sqliteConstraintPrimaryKey: return xerrors.New(xerrors.ErrAlreadyExists, "record already exists").WithError(err) case sqliteConstraintForeignKey: return xerrors.New(xerrors.ErrInvalidInput, "data integrity violation").WithError(err) } } return xerrors.New(xerrors.ErrInternal, "unexpected database error").WithError(err) }