template

package module
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 1 Imported by: 0

README

gas-template

Test Go Reference Go Version License

Template storage service for the Gas ecosystem. Provides multiple gas.TemplateProvider implementations — in-memory, filesystem, database, and composite — for storing and retrieving raw template content.

Install

go get github.com/gasmod/gas-template

Backends

Backend Package Use case
Memory github.com/gasmod/gas-template/memory Development, testing, ephemeral storage
Directory github.com/gasmod/gas-template/dir Static templates on disk with runtime overlay
FS github.com/gasmod/gas-template/fs Read-only adapter for fs.FS (e.g. embed.FS)
Database github.com/gasmod/gas-template/db Persistent, multi-instance deployments (Pg/MySQL/SQLite)
Composite github.com/gasmod/gas-template/composite Chain multiple providers with fallback reads

Memory, directory, fs, and composite stores implement gas.TemplateProvider. The database store also implements gas.Service (with DI, migrations, and lifecycle management).

Usage

Memory backend
import "github.com/gasmod/gas-template/memory"

store := memory.NewStore()
if err := store.Register(ctx, "emails/welcome.html", []byte("<h1>Welcome</h1>")); err != nil {
    // handle error
}

content, err := store.Get(ctx, "emails/welcome.html")
Directory backend
import "github.com/gasmod/gas-template/dir"

// NewStore returns a DI-injectable constructor; call it to get a *Store.
store := dir.NewStore("./templates")()
defer store.Close()

// Reads from disk; overlay takes precedence.
content, err := store.Get(ctx, "home.html")

// Programmatic additions go to the in-memory overlay.
_ = store.Register(ctx, "dynamic.html", []byte("<p>Dynamic</p>"))
FS backend

Read-only adapter for any fs.FS — most commonly an embed.FS. Register and RegisterFS return template.ErrReadOnly; wrap in a composite store with a writable provider for mutability.

import (
    "embed"

    tmplfs "github.com/gasmod/gas-template/fs"
)

//go:embed templates/*.html
var templateFS embed.FS

// NewStore returns a DI-injectable constructor; call it to get a *Store.
store := tmplfs.NewStore(templateFS)()
content, err := store.Get(ctx, "templates/home.html")
Database backend
package main

import (
    "github.com/gasmod/gas"
    database "github.com/gasmod/gas-database"
    migrate "github.com/gasmod/gas-migrate"
    tmpldb "github.com/gasmod/gas-template/db"
)

func main() {
    app := gas.NewApp(
        gas.WithSingletonService[*database.Service](database.New()),
        gas.WithSingletonService[*migrate.Service](migrate.New()),
        gas.WithSingletonService[*tmpldb.Store](tmpldb.NewStore()),
        // ...
    )

    app.Run()
}

With a custom namespace:

tmpldb.NewStore(tmpldb.WithNamespace("emails"))
Composite backend

Chain multiple providers — writes go to the first, reads fall back through all:

import (
    "github.com/gasmod/gas-template/composite"
    "github.com/gasmod/gas-template/memory"
    "github.com/gasmod/gas-template/dir"
)

writable := memory.NewStore()
disk := dir.NewStore("./templates")()
defer disk.Close()

store := composite.NewStore(writable, disk)

// Get checks writable first, then disk.
content, err := store.Get(ctx, "page.html")

// Register goes to the writable provider only.
_ = store.Register(ctx, "override.html", []byte("<p>Override</p>"))
Dependency injection

Services receive templates through gas.TemplateProvider via constructor injection:

type Service struct {
    templates gas.TemplateProvider
}

func New(templates gas.TemplateProvider) *Service {
    return &Service{templates: templates}
}

func (s *Service) Init() error {
    content, err := s.templates.Get(context.Background(), "emails/welcome.html")
    if err != nil {
        return err
    }
    // use content...
    return nil
}
Registering templates from embedded files

All writable stores (memory, dir, db) support loading templates from an fs.FS via RegisterFS:

import "embed"

//go:embed templates/*.html
var templateFS embed.FS

if err := store.RegisterFS(ctx, templateFS); err != nil {
    // handle error
}

Only .html files are registered; other extensions are skipped. For a read-only view over an fs.FS without copying contents into another store, use the fs backend instead.

Database Backends

The db package supports three database dialects. The correct dialect is selected automatically based on the configured database driver:

Driver Dialect
postgres, pgx PostgreSQL
mysql MySQL
sqlite, sqlite3 SQLite

The templates table migration is registered automatically with gas-migrate during Init().

Namespaces

Multiple db.Store instances can share the same table by using different namespaces:

gas.WithSingletonService[*tmpldb.Store](tmpldb.NewStore(tmpldb.WithNamespace("emails")))

The default namespace is "default".

Extra methods

The database store exposes two additional methods beyond gas.TemplateProvider:

store.Exists("page.html")  // (bool, error)
store.Delete("page.html")  // error — returns template.ErrTemplateNotFound if missing

Testing

The templatetest package provides a mock implementation of gas.TemplateProvider:

import "github.com/gasmod/gas-template/templatetest"

mock := &templatetest.MockTemplate{}
mock.GetFn = func(ctx context.Context, name string) ([]byte, error) {
    return []byte("<h1>Hello</h1>"), nil
}

// pass mock as gas.TemplateProvider
// assert calls:
if mock.CallCount("Get") != 1 {
    t.Error("expected one Get call")
}

Sentinel Errors

The root template package defines a sentinel error used by all backends:

template.ErrTemplateNotFound // returned by Get when the template does not exist
template.IsNotFound(err)     // helper to check if an error is ErrTemplateNotFound

Documentation

Overview

Package template provides template storage and retrieval for the Gas ecosystem with in-memory, directory, database, filesystem, and composite backends in the memory, dir, db, fs, and composite sub-packages.

See the module README for usage examples and design rationale.

SPDX-License-Identifier: MIT

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrTemplateNotFound is returned by Get when the requested template
	// does not exist.
	ErrTemplateNotFound = errors.New("template: not found")

	// ErrReadOnly is returned by Register and RegisterFS on read-only
	// providers (e.g. the fs backend). Wrap such providers in a composite
	// store with a writable provider if mutation is required.
	ErrReadOnly = errors.New("template: read-only provider")
)

Sentinel errors returned by TemplateProvider implementations.

Functions

func IsNotFound

func IsNotFound(err error) bool

IsNotFound returns true if the given error is an ErrTemplateNotFound. Useful for callers that need to distinguish "not found" from other errors.

Types

This section is empty.

Directories

Path Synopsis
db
Package fs provides a read-only template store backed by an fs.FS, suitable for use with embed.FS or any other fs.FS implementation.
Package fs provides a read-only template store backed by an fs.FS, suitable for use with embed.FS or any other fs.FS implementation.
internal
Package templatetest provides a mock implementation of gas.TemplateProvider for use in tests.
Package templatetest provides a mock implementation of gas.TemplateProvider for use in tests.

Jump to

Keyboard shortcuts

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