Architecture
System Position
scio sits between your application logic and storage providers:
Application Layer
│
▼
┌─────┐
│scio │ ← URI routing, catalog, spec tracking
└──┬──┘
│
▼
┌──────────────┐
│ grub Atomic │ ← Type-agnostic interfaces
│ Interfaces │
└──────┬───────┘
│
▼
┌──────────────┐
│ grub │ ← Typed wrappers
│ Wrappers │
└──────┬───────┘
│
▼
┌──────────────┐
│ Providers │ ← Redis, PostgreSQL, S3, etc.
└──────────────┘
Data Flow
Registration
User Code scio grub
│ │ │
│ NewDatabase[User]() │ │
│ ─────────────────────────┼───────────────────────▶│
│ │ │
│ .Atomic() │ │
│ ─────────────────────────┼───────────────────────▶│
│ │ AtomicDatabase │
│ │◀───────────────────────│
│ │ │
│ RegisterDatabase() │ │
│ ────────────────────────▶│ │
│ │ Store by URI │
│ │ Track spec │
Operations
Caller scio Provider
│ │ │
│ Get("db://users/123") │ │
│ ─────────────────────────▶│ │
│ │ Parse URI │
│ │ Lookup provider │
│ │ │
│ │ Get(ctx, "123") │
│ │───────────────────────▶│
│ │ │
│ │ *atom.Atom │
│ *atom.Atom │◀───────────────────────│
│◀──────────────────────────│ │
Thread Safety
scio uses sync.RWMutex for thread-safe access:
- Registration operations acquire write lock
- Read operations (Get, Exists, catalog queries) acquire read lock
- Multiple readers can operate concurrently
Error Handling
scio uses semantic errors:
// scio-specific errors
scio.ErrInvalidURI // URI parsing failed
scio.ErrUnknownVariant // Unknown scheme
scio.ErrResourceNotFound // Resource not registered
scio.ErrResourceExists // Duplicate registration
scio.ErrVariantMismatch // Wrong operation for variant
scio.ErrKeyRequired // Missing key in URI
scio.ErrKeyNotExpected // Key provided but not used (Query/Select)
// Passed through from grub
scio.ErrNotFound // Record doesn't exist
scio.ErrDuplicate // Key already exists
Integration Patterns
Service Layer
type UserService struct {
catalog *scio.Scio
}
func (s *UserService) GetUser(ctx context.Context, id string) (*atom.Atom, error) {
return s.catalog.Get(ctx, "db://users/"+id)
}
Middleware
func DataContextMiddleware(s *scio.Scio) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), "scio", s)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}