docstore

package module
v1.2.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 31, 2025 License: MIT Imports: 12 Imported by: 0

README

Docstore

docstore is a simple, in-memory, key-value document store in Go. It is thread-safe and supports persistence through GOB serialization.

Documents can be of any type. The store is a package-level singleton, providing straightforward functions like Put, Get, GetAs, and Delete.

Features

  • In-memory key-value store.
  • Thread-safe operations.
  • Support for any Go type as a document.
  • Generic-aware GetAs[T] for type-safe retrieval.
  • Manual persistence to disk via GOB serialization.
  • GZIP compression for saved stores.
  • A generic HTTP server for exposing a store of a specific type over a REST-like API.

Getting Started

To use docstore in your Go project, you can install it using go get:

go get github.com/schraf/docstore

Usage Example

Because docstore uses GOB for serialization, you must register the types of the documents you want to store.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/schraf/docstore"
)

// Define your document structure.
type MyNote struct {
	Title string
	Body  string
}

func main() {
	// Register your document type for serialization.
	docstore.RegisterType[MyNote]()

	// Create a new document ID.
	id := docstore.GenerateDocId()
	note := MyNote{
		Title: "Hello",
		Body:  "This is my first note in the docstore!",
	}

	// Add the document to the store.
	if err := docstore.Put(id, note); err != nil {
		log.Fatalf("Failed to put document: %v", err)
	}
	fmt.Println("Successfully stored a new note.")

	// Retrieve the document with type assertion.
	retrievedNote, err := docstore.GetAs[MyNote](id)
	if err != nil {
		log.Fatalf("Failed to get document: %v", err)
	}
	fmt.Printf("Retrieved note: %+v\n", *retrievedNote)

	// --- Persistence ---

	// Create a temporary file to save the store.
	file, err := os.CreateTemp("", "docstore-*.gz")
	if err != nil {
		log.Fatalf("Failed to create temp file: %v", err)
	}
	defer os.Remove(file.Name())

	// Save the entire store to the file (compressed).
	if err := docstore.WriteAllToFile(file.Name()); err != nil {
		log.Fatalf("Failed to save store: %v", err)
	}
	fmt.Printf("Store saved to %s\n", file.Name())

	// Clear the in-memory store to simulate a restart.
	docstore.Clear()
	fmt.Println("In-memory store cleared.")

	// Load the store back from the file.
	if err := docstore.ReadAllFromFile(file.Name()); err != nil {
		log.Fatalf("Failed to load store: %v", err)
	}
	fmt.Println("Store loaded from file.")

	// Verify the document was restored.
	reloadedNote, err := docstore.GetAs[MyNote](id)
	if err != nil {
		log.Fatalf("Failed to get document after reload: %v", err)
	}
	fmt.Printf("Reloaded note: %+v\n", *reloadedNote)
}
HTTP Server Example

The Server is generic and designed to serve a store for a single, specific document type.

package main

import (
	"log"
	"net/http"

	"github.com/schraf/docstore"
)

type UserProfile struct {
	Name  string
	Email string
}

func main() {
	// Register the type for both serialization and the server.
	docstore.RegisterType[UserProfile]()

	// Register the HTTP handlers on a new mux.
	mux := http.NewServeMux()
	RegisterHandlers[UserProfile]("/users", mux)

	log.Println("Server listening on :8080")
	if err := http.ListenAndServe(":8080", mux); err != nil {
		log.Fatal(err)
	}
}

You can then interact with it using curl (requires Go 1.22+ for path-based routing):

# Create or update a user profile
curl -X POST -d '{"name": "John Doe", "email": "[email protected]"}' http://localhost:8080/users/john

# Retrieve the user profile
curl http://localhost:8080/users/john

# Delete the user profile
curl -X DELETE http://localhost:8080/users/john

Development

This project uses a Makefile to automate common development tasks.

Installing Dependencies

To install the dependencies, run:

make deps
Running Tests

To run the tests for this project, use the test target in the Makefile:

make test

This will run all tests, shuffle their execution order, and run each test 3 times to help detect flaky tests.

Formatting Code

To format the Go source code, run:

make fmt
Vetting Code

To run go vet on the codebase, use:

make vet

Documentation

Index

Constants

View Source
const EmptyDocId = DocId("")

EmptyDocId is an empty document identifier.

Variables

View Source
var (
	// ErrDocumentNotFound is returned when a document is not found.
	ErrDocumentNotFound = errors.New("document not found")

	// ErrEmptyDocumentId is returned when a valid document id is required.
	ErrEmptyDocumentId = errors.New("empty document id")

	// ErrDocumentTypeMismatch is returned when a document type does not match the expected type
	ErrDocumentTypeMismatch = errors.New("document type mismatch")
)

Functions

func AllDocuments added in v1.2.4

func AllDocuments() iter.Seq2[DocId, Document]

AllDocuments returns a iterator that goes over all stored documents

func AllDocumentsOf added in v1.2.4

func AllDocumentsOf[T Document]() iter.Seq2[DocId, T]

AllDocumentsOf returns a iterator that goes over all stored documents of a given type

func Clear added in v1.2.0

func Clear()

Clear removes all documents from the store.

func Delete added in v1.2.0

func Delete(id DocId) error

Delete removes a document

func DeleteAllOf added in v1.2.5

func DeleteAllOf[T Document]() int

DeleteAllOf removes all documents of the given type returns the number of documents deleted

func DeleteHandler added in v1.2.1

func DeleteHandler[T Document]() http.HandlerFunc

DeleteHandler returns an http.HandlerFunc for deleting a document. It expects the document ID to be in the URL path (e.g., /docs/my-doc-id).

func GetAs added in v1.2.0

func GetAs[T Document](id DocId) (*T, error)

GetAs retrieves a typed document by Id

func GetHandler added in v1.2.1

func GetHandler[T Document]() http.HandlerFunc

GetHandler returns an http.HandlerFunc for retrieving a document. It expects the document ID to be in the URL path (e.g., /docs/my-doc-id).

func ListHandler added in v1.2.4

func ListHandler[T Document]() http.HandlerFunc

ListHandler returns an http.HandlerFunc for retrieving all documents of the given type

func Put added in v1.2.0

func Put(id DocId, doc Document) error

Put adds a document to the store.

func PutHandler added in v1.2.1

func PutHandler[T Document]() http.HandlerFunc

PutHandler returns an http.HandlerFunc for adding or updating a document. It expects a POST request with a JSON body representing the full document. On success, it returns status 204

func ReadAll added in v1.2.0

func ReadAll(r io.Reader) error

ReadAll reads all of the documents from the given reader.

func ReadAllFromFile added in v1.2.0

func ReadAllFromFile(filename string) (err error)

ReadAllFromFile reads the entire docstore from a single file, replacing any contents that were in the docstore.

func RegisterHandlers added in v1.2.1

func RegisterHandlers[T Document](prefix string, mux *http.ServeMux)

RegisterHandlers registers the store handlers on a ServeMux. This uses the path-based routing available in Go 1.22+. For example, if you provide "/api/docs", it will register: - POST /api/docs/{id} - GET /api/docs/{id} - DELETE /api/docs/{id}

func RegisterType added in v1.2.0

func RegisterType[T Document]()

RegisterType registers the given document type with the gob package. This is necessary so that the gob package knows how to encode and decode the document type.

func WriteAll added in v1.2.0

func WriteAll(w io.Writer) error

WriteAll writes all of the documents to the given writer.

func WriteAllToFile added in v1.2.0

func WriteAllToFile(filename string) (err error)

WriteAllToFile writes the entire docstore to a single file.

Types

type DocId

type DocId string

DocId is a document identifier.

func GenerateDocId

func GenerateDocId() DocId

GenerateDocId creates a new random document identifier.

func NewDocId

func NewDocId(id string) DocId

NewDocId creates a new document identifier.

func (DocId) String

func (d DocId) String() string

String returns the string representation of the document identifier.

type Document

type Document any

Document is the document to be stored.

func Get added in v1.2.0

func Get(id DocId) (*Document, error)

Get retrieves a document by Id

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL