Documentation
¶
Overview ¶
Package loam is the Composition Root for the Loam application.
It connects the core business logic (Domain Layer) with the infrastructure adapters (Persistence Layer) using the Hexagonal Architecture pattern.
Philosophy:
Loam is a "Headless CMS" for toolmakers. It treats a collection of documents as a transactional database, abstracting the underlying storage mechanism. While the default implementation uses the File System and Git, Loam's core is agnostic, allowing for future adapters (e.g., S3, SQLite).
Features:
- **Hexagonal Architecture**: Core domain is isolated from persistence details.
- **Transactional Safe**: Atomic operations regardless of the underlying storage.
- **Metadata First**: Native support for structured metadata indexing (Frontmatter, JSON fields, etc).
- **Typed Retrieval**: Generic wrapper (`NewTyped[T]`) for type-safe document access.
- **Default Adapter (FS + Git)**: Out-of-the-box support for local Markdown files with Git versioning.
- **Extensible**: Designed to support other backends (SQL, S3, NoSQL) via `core.Repository`.
Usage:
// Initialize service with functional options
svc, err := loam.New("./vault",
loam.WithAutoInit(true),
loam.WithLogger(logger),
)
// Save a note
err := svc.SaveNote(ctx, "my-note", "content", nil)
Example (Basic) ¶
Example_basic demonstrates how to initialize a Vault, save a note, and read it back.
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/aretw0/loam"
"github.com/aretw0/loam/pkg/core"
)
func main() {
// Create a temporary directory for the example
tmpDir, err := os.MkdirTemp("", "loam-example-*")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Initialize the Loam service (Vault) targeting the temporary directory.
// WithAutoInit(true) ensures the underlying storage (git repo) is initialized.
vault, err := loam.New(tmpDir, loam.WithAutoInit(true))
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// 1. Save a Document
err = vault.SaveDocument(ctx, "hello-world", "This is my first note in Loam.", core.Metadata{
"tags": []string{"example"},
"author": "Gopher",
})
if err != nil {
log.Fatal(err)
}
// 2. Read it back
doc, err := vault.GetDocument(ctx, "hello-world")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found document: %s\n", doc.ID)
}
Output: Found document: hello-world
Index ¶
- Constants
- Variables
- func AppendFooter(msg string) string
- func FormatChangeReason(ctype, scope, subject, body string) string
- func Init(path string, opts ...Option) (core.Repository, error)
- func IsDevRun() bool
- func New(path string, opts ...Option) (*core.Service, error)
- func ResolveVaultPath(userPath string, forceTemp bool) string
- func Sync(path string, opts ...Option) error
- type DocumentModel
- type Option
- func WithAdapter(name string) Option
- func WithAutoInit(auto bool) Option
- func WithForceTemp(force bool) Option
- func WithLogger(logger *slog.Logger) Option
- func WithMustExist(must bool) Option
- func WithRepository(repo core.Repository) Option
- func WithSystemDir(name string) Option
- func WithVersioning(enabled bool) Option
- type TypedRepository
Examples ¶
Constants ¶
const ( CommitTypeFeat = platform.CommitTypeFeat CommitTypeFix = platform.CommitTypeFix CommitTypeDocs = platform.CommitTypeDocs CommitTypeStyle = platform.CommitTypeStyle CommitTypeRefactor = platform.CommitTypeRefactor CommitTypePerf = platform.CommitTypePerf CommitTypeTest = platform.CommitTypeTest CommitTypeChore = platform.CommitTypeChore )
Variables ¶
var Version string
Functions ¶
func AppendFooter ¶ added in v0.5.1
AppendFooter appends the Loam footer to an arbitrary message.
func FormatChangeReason ¶ added in v0.5.1
FormatChangeReason builds a Conventional Commit message.
func Init ¶ added in v0.5.1
func Init(path string, opts ...Option) (core.Repository, error)
Init initializes a repository explicitly.
func IsDevRun ¶ added in v0.5.1
func IsDevRun() bool
IsDevRun checks if the current process is running via `go run` or `go test`.
func ResolveVaultPath ¶ added in v0.5.1
ResolveVaultPath determines the actual path for the vault based on safety rules.
Types ¶
type DocumentModel ¶ added in v0.6.0
type DocumentModel[T any] = platform.DocumentModel[T]
DocumentModel wraps the raw core.Document with a typed Metadata field. It is the generic equivalent of core.Document.
type Option ¶ added in v0.5.1
Option defines a functional option for configuring Loam.
func WithAdapter ¶ added in v0.5.1
WithAdapter allows specifying the storage adapter to use by name.
func WithAutoInit ¶ added in v0.5.1
WithAutoInit enables automatic initialization of the vault (git init).
func WithForceTemp ¶ added in v0.5.1
WithForceTemp forces the use of a temporary directory (useful for testing).
func WithLogger ¶ added in v0.5.1
WithLogger sets the logger for the service.
func WithMustExist ¶ added in v0.5.1
WithMustExist ensures the vault directory must already exist.
func WithRepository ¶ added in v0.5.1
func WithRepository(repo core.Repository) Option
WithRepository allows injecting a custom storage adapter.
func WithSystemDir ¶ added in v0.6.0
WithSystemDir allows specifying the hidden directory name (e.g. ".loam").
func WithVersioning ¶ added in v0.5.1
WithVersioning enables or disables version control (e.g. Git).
type TypedRepository ¶ added in v0.6.0
type TypedRepository[T any] = platform.TypedRepository[T]
TypedRepository wraps a core.Repository to provide type-safe access. It acts as an Application Layer adapter, converting between raw maps and typed structs.
func NewTyped ¶ added in v0.6.0
func NewTyped[T any](repo core.Repository) *TypedRepository[T]
NewTyped creates a new type-safe repository wrapper. T is the type of the struct you want to store in the document metadata.
Example ¶
Example_typed demonstrates how to use the Generic Typed Wrapper for type safety.
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"github.com/aretw0/loam"
)
func main() {
// Setup: Temporary repository
tmpDir, err := os.MkdirTemp("", "loam-typed-example-*")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Use loam.Init to get the Repository directly
repo, err := loam.Init(filepath.Join(tmpDir, "vault"), loam.WithAutoInit(true))
if err != nil {
log.Fatal(err)
}
// Define your Domain Model
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
// Wrap the repository
userRepo := loam.NewTyped[User](repo)
ctx := context.Background()
// Save a typed document
err = userRepo.Save(ctx, &loam.DocumentModel[User]{
ID: "users/alice",
Content: "Alice's Profile",
Data: User{
Name: "Alice",
Email: "alice@example.com",
},
})
if err != nil {
log.Fatal(err)
}
// Retrieve it back
doc, err := userRepo.Get(ctx, "users/alice")
if err != nil {
log.Fatal(err)
}
fmt.Printf("User Name: %s\n", doc.Data.Name)
}
Output: User Name: Alice
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
loam
command
|
|
|
examples
|
|
|
demos/formats
command
|
|
|
demos/typed
command
|
|
|
recipes/etl_migration
command
|
|
|
internal
|
|
|
pkg
|
|
|
core
Document is the central entity of the domain.
|
Document is the central entity of the domain. |