shithub: furgit

Download patch

ref: 3b44bb05f74ebd2734f12808c813dae2995b41b1
parent: e42ad9964d9c9372ecb63c860ed2c91b09b373b2
author: Runxi Yu <me@runxiyu.org>
date: Fri Feb 20 19:11:00 EST 2026

objectdb: Add Reader-based methods

--- a/objectdb/chain.go
+++ b/objectdb/chain.go
@@ -3,6 +3,7 @@
 import (
 	"errors"
 	"fmt"
+	"io"
 
 	"codeberg.org/lindenii/furgit/objectid"
 	"codeberg.org/lindenii/furgit/objecttype"
@@ -52,6 +53,42 @@
 			continue
 		}
 		return objecttype.TypeInvalid, nil, fmt.Errorf("objectdb: backend %d read bytes content: %w", i, err)
+	}
+	return objecttype.TypeInvalid, nil, ErrObjectNotFound
+}
+
+// ReadReaderFull reads a full serialized object stream from the first backend that has it.
+func (chain *Chain) ReadReaderFull(id objectid.ObjectID) (io.ReadCloser, error) {
+	for i, backend := range chain.backends {
+		if backend == nil {
+			continue
+		}
+		reader, err := backend.ReadReaderFull(id)
+		if err == nil {
+			return reader, nil
+		}
+		if errors.Is(err, ErrObjectNotFound) {
+			continue
+		}
+		return nil, fmt.Errorf("objectdb: backend %d read reader full: %w", i, err)
+	}
+	return nil, ErrObjectNotFound
+}
+
+// ReadReaderContent reads an object's type and content stream from the first backend that has it.
+func (chain *Chain) ReadReaderContent(id objectid.ObjectID) (objecttype.Type, io.ReadCloser, error) {
+	for i, backend := range chain.backends {
+		if backend == nil {
+			continue
+		}
+		ty, reader, err := backend.ReadReaderContent(id)
+		if err == nil {
+			return ty, reader, nil
+		}
+		if errors.Is(err, ErrObjectNotFound) {
+			continue
+		}
+		return objecttype.TypeInvalid, nil, fmt.Errorf("objectdb: backend %d read reader content: %w", i, err)
 	}
 	return objecttype.TypeInvalid, nil, ErrObjectNotFound
 }
--- a/objectdb/objectdb.go
+++ b/objectdb/objectdb.go
@@ -3,6 +3,7 @@
 
 import (
 	"errors"
+	"io"
 
 	"codeberg.org/lindenii/furgit/objectid"
 	"codeberg.org/lindenii/furgit/objecttype"
@@ -19,6 +20,12 @@
 	ReadBytesFull(id objectid.ObjectID) ([]byte, error)
 	// ReadBytesContent reads an object's type and content bytes.
 	ReadBytesContent(id objectid.ObjectID) (objecttype.Type, []byte, error)
+	// ReadReaderFull reads a full serialized object stream as "type size\\x00content".
+	// Caller must close the returned reader.
+	ReadReaderFull(id objectid.ObjectID) (io.ReadCloser, error)
+	// ReadReaderContent reads an object's type and content stream.
+	// Caller must close the returned reader.
+	ReadReaderContent(id objectid.ObjectID) (objecttype.Type, io.ReadCloser, error)
 	// ReadHeader reads an object's type and declared content length.
 	ReadHeader(id objectid.ObjectID) (objecttype.Type, int64, error)
 	// Close releases resources associated with the backend.
--