Warden

Custom Store

Implement a custom store backend for Warden.

You can implement a custom store by satisfying the store.Store interface.

Store Interface

The composite store interface embeds all subsystem stores:

import "github.com/xraph/warden/store"

type Store interface {
    role.Store
    permission.Store
    assignment.Store
    relation.Store
    policy.Store
    resourcetype.Store
    checklog.Store

    Migrate(ctx context.Context) error
    Ping(ctx context.Context) error
    Close() error
}

Subsystem Interfaces

Each subsystem defines its own store interface. Here's an overview:

role.Store

type Store interface {
    CreateRole(ctx context.Context, r *Role) error
    GetRole(ctx context.Context, id id.RoleID) (*Role, error)
    UpdateRole(ctx context.Context, r *Role) error
    DeleteRole(ctx context.Context, id id.RoleID) error
    ListRoles(ctx context.Context, filter *ListFilter) ([]*Role, error)
    CountRoles(ctx context.Context, filter *ListFilter) (int, error)
    AttachPermission(ctx context.Context, roleID id.RoleID, permID id.PermissionID) error
    DetachPermission(ctx context.Context, roleID id.RoleID, permID id.PermissionID) error
    ListPermissionsForRole(ctx context.Context, roleID id.RoleID) ([]id.PermissionID, error)
    GetRoleBySlug(ctx context.Context, slug string) (*Role, error)
    ListChildRoles(ctx context.Context, parentID id.RoleID) ([]*Role, error)
    ListRolesForSubject(ctx context.Context, tenantID, subjectKind, subjectID string) ([]id.RoleID, error)
    DeleteByTenant(ctx context.Context, tenantID string) error
}

Other subsystem stores follow the same pattern:

  • permission.Store — CRUD + role attachment queries
  • assignment.Store — CRUD + subject/role lookups
  • relation.Store — CRUD + graph traversal queries
  • policy.Store — CRUD + active policy lookups
  • resourcetype.Store — CRUD + name lookups
  • checklog.Store — Append + query

Implementation Tips

  1. Start with the memory store as a reference: store/memory/store.go
  2. Use compile-time checks to ensure interface compliance:
    var _ store.Store = (*MyStore)(nil)
  3. Thread safety — Use appropriate locking for concurrent access
  4. Tenant isolation — All queries should filter by tenant ID from context
  5. Error mapping — Return warden.ErrNotFound for missing entities, warden.ErrAlreadyExists for duplicates

Example Skeleton

package mystore

import (
    "context"
    "github.com/xraph/warden/store"
)

type MyStore struct {
    // your database client
}

var _ store.Store = (*MyStore)(nil)

func (s *MyStore) Migrate(ctx context.Context) error {
    // Run migrations
    return nil
}

func (s *MyStore) Ping(ctx context.Context) error {
    // Health check
    return nil
}

func (s *MyStore) Close() error {
    // Close connections
    return nil
}

// Implement all subsystem store methods...

On this page