zoobzio January 6, 2025 Edit this page

Provider Reference

Provider-specific behaviors, limitations, and configuration options.

Key-Value Providers

Redis

import "github.com/zoobz-io/grub/redis"

Constructor

func New(client *redis.Client) *Provider

Accepts *redis.Client, *redis.ClusterClient, or any client implementing the required interface.

client := goredis.NewClient(&goredis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
})
provider := redis.New(client)

Behaviors

OperationImplementation
GetGET command
SetSET with EX option
DeleteDEL command
ExistsEXISTS command
ListSCAN with MATCH
GetBatchMGET command
SetBatchPipelined SET

Features

FeatureSupport
TTLFull (native)
Batch atomicityNo (pipelined)
DistributedYes

Error Mapping

Redis ErrorGrub Error
redis.NilErrNotFound

Notes

  • List uses SCAN, which is safe for production (non-blocking)
  • SetBatch uses pipelining (each SET is independent)
  • Cluster mode supported via *redis.ClusterClient

BadgerDB

import "github.com/zoobz-io/grub/badger"

Constructor

func New(db *badger.DB) *Provider
opts := badgerdb.DefaultOptions("./data")
opts.Logger = nil
db, _ := badgerdb.Open(opts)
provider := badger.New(db)

Behaviors

OperationImplementation
GetView transaction
SetUpdate transaction with Entry
DeleteUpdate transaction
ExistsView transaction
ListIterator with prefix
GetBatchView transaction
SetBatchWriteBatch

Features

FeatureSupport
TTLFull (Entry.WithTTL)
Batch atomicityYes (WriteBatch)
EmbeddedYes
EncryptionYes (Badger native)

Error Mapping

Badger ErrorGrub Error
badger.ErrKeyNotFoundErrNotFound

Configuration Options

opts := badgerdb.DefaultOptions(path)
opts.Logger = nil                    // Silence logs
opts.ValueLogFileSize = 64 << 20     // 64MB value log
opts.NumMemtables = 2                // Memory tables
opts.NumLevelZeroTables = 2          // L0 tables

In-Memory Mode

opts := badgerdb.DefaultOptions("").WithInMemory(true)

BoltDB

import "github.com/zoobz-io/grub/bolt"

Constructor

func New(db *bbolt.DB, bucket string) *Provider

bucket is the BoltDB bucket name for data storage.

db, _ := bbolt.Open("my.db", 0600, nil)
provider := bolt.New(db, "sessions")

Behaviors

OperationImplementation
GetView transaction
SetUpdate transaction
DeleteUpdate transaction
ExistsView transaction
ListCursor iteration
GetBatchView transaction
SetBatchSingle Update transaction

Features

FeatureSupport
TTLNot supported
Batch atomicityYes
EmbeddedYes
Multiple storesYes (via bucket name)

Error Mapping

ConditionGrub Error
Key not in bucketErrNotFound
TTL > 0ErrTTLNotSupported

Notes

  • TTL is not supported. Set with ttl > 0 returns ErrTTLNotSupported
  • Multiple stores can share one DB file using different bucket names
  • Auto-creates bucket on first write

Multiple Buckets

db, _ := bbolt.Open("app.db", 0600, nil)
sessions := grub.NewStore[Session](bolt.New(db, "sessions"))
configs := grub.NewStore[Config](bolt.New(db, "configs"))

Blob Storage Providers

AWS S3

import "github.com/zoobz-io/grub/s3"

Constructor

func New(client *s3.Client, bucket string) *Provider
cfg, _ := config.LoadDefaultConfig(ctx)
client := awss3.NewFromConfig(cfg)
provider := s3.New(client, "my-bucket")

Behaviors

OperationImplementation
GetGetObject
PutPutObject
DeleteHeadObject + DeleteObject
ExistsHeadObject
ListListObjectsV2

Features

FeatureSupport
MetadataYes
ContentTypeYes
ETagYes (from response)

Error Mapping

S3 ErrorGrub Error
NoSuchKeyErrNotFound

Notes

  • Delete checks Exists first (S3 DeleteObject succeeds on missing keys)
  • List uses continuation tokens for pagination
  • Metadata preserved in ObjectInfo

Custom Endpoint (LocalStack)

client := awss3.NewFromConfig(cfg, func(o *awss3.Options) {
    o.BaseEndpoint = aws.String("http://localhost:4566")
    o.UsePathStyle = true
})

MinIO

import "github.com/zoobz-io/grub/minio"

Constructor

func New(client *minio.Client, bucket string) *Provider
client, _ := minio.New("localhost:9000", &minio.Options{
    Creds:  credentials.NewStaticV4("minioadmin", "minioadmin", ""),
    Secure: false,
})
provider := grubminio.New(client, "my-bucket")

Behaviors

OperationImplementation
GetGetObject + Stat
PutPutObject
DeleteStatObject + RemoveObject
ExistsStatObject
ListListObjects (channel)

Features

FeatureSupport
MetadataYes (UserMetadata)
ContentTypeYes
ETagYes (from stat)

Error Mapping

MinIO ErrorGrub Error
ErrorResponse.Code == "NoSuchKey"ErrNotFound

Notes

  • Delete checks Exists first (RemoveObject succeeds on missing keys)
  • List uses channel-based iteration with recursive option
  • Uses minio-go/v7 — lighter dependency than aws-sdk-go-v2
  • Metadata mapped via ObjectInfo.UserMetadata

Google Cloud Storage

import "github.com/zoobz-io/grub/gcs"

Constructor

func New(client *storage.Client, bucket string) *Provider
client, _ := storage.NewClient(ctx)
provider := gcs.New(client, "my-bucket")

Behaviors

OperationImplementation
GetNewReader + ReadAll
PutNewWriter
DeleteDelete
ExistsAttrs
ListObjects iterator

Features

FeatureSupport
MetadataYes
ContentTypeYes (writer.ContentType)
ETagYes (Etag from attrs)

Error Mapping

GCS ErrorGrub Error
storage.ErrObjectNotExistErrNotFound

Azure Blob Storage

import "github.com/zoobz-io/grub/azure"

Constructor

func New(client *azblob.Client, containerName string) *Provider
cred, _ := azidentity.NewDefaultAzureCredential(nil)
client, _ := azblob.NewClient("https://account.blob.core.windows.net/", cred, nil)
provider := azure.New(client, "my-container")

Behaviors

OperationImplementation
GetDownloadStream
PutUploadBuffer
DeleteDelete
ExistsGetProperties
ListNewListBlobsFlatPager

Features

FeatureSupport
MetadataYes (may need GetProperties)
ContentTypeYes
ETagYes (from properties)

Error Mapping

Azure ErrorGrub Error
bloberror.BlobNotFoundErrNotFound

Notes

  • Metadata may require separate GetProperties call after download
  • Azure uses map[string]*string for metadata (converted internally)

SQL Driver Modules

Thin wrappers that register database drivers.

PostgreSQL

import _ "github.com/zoobz-io/grub/postgres"

Registers github.com/lib/pq driver.

import (
    _ "github.com/zoobz-io/grub/postgres"
    "github.com/zoobz-io/astql/postgres"
)

db, _ := sqlx.Connect("postgres", dsn)
users, _ := grub.NewDatabase[User](db, "users", postgres.New())

MariaDB

import _ "github.com/zoobz-io/grub/mariadb"

Registers github.com/go-sql-driver/mysql driver (MariaDB uses MySQL wire protocol).

import (
    _ "github.com/zoobz-io/grub/mariadb"
    "github.com/zoobz-io/astql/mariadb"
)

db, _ := sqlx.Connect("mysql", dsn)

SQLite

import _ "github.com/zoobz-io/grub/sqlite"

Registers modernc.org/sqlite driver (pure Go, no CGO).

import (
    _ "github.com/zoobz-io/grub/sqlite"
    "github.com/zoobz-io/astql/sqlite"
)

db, _ := sqlx.Connect("sqlite", "./data.db")

In-Memory

db, _ := sqlx.Connect("sqlite", ":memory:")

SQL Server

import _ "github.com/zoobz-io/grub/mssql"

Registers github.com/microsoft/go-mssqldb driver.

import (
    _ "github.com/zoobz-io/grub/mssql"
    "github.com/zoobz-io/astql/mssql"
)

db, _ := sqlx.Connect("sqlserver", dsn)

Provider Comparison

Key-Value Features

FeatureRedisBadgerBolt
TTL
Batch atomicity
Embedded
Distributed
Encryption
In-memory mode

Blob Features

FeatureS3MinIOGCSAzure
Metadata
ContentType
ETag
Versioning

Error Semantics

All providers map their native errors to grub semantic errors:

Semantic ErrorMeaning
ErrNotFoundKey/object doesn't exist
ErrTTLNotSupportedProvider can't handle TTL
ErrOperatorNotSupportedVector provider doesn't support filter operator
ErrInvalidQueryFilter contains validation errors
ErrFilterNotSupportedVector provider doesn't support metadata-only filtering

Context Cancellation

ProviderCancellation Support
RedisAll operations
BadgerIteration
BoltIteration
S3All operations
MinIOAll operations
GCSAll operations
AzureAll operations
QdrantAll operations
PineconeAll operations
MilvusAll operations
WeaviateAll operations

Vector Providers

Qdrant

import "github.com/zoobz-io/grub/qdrant"

Constructor

func New(client *qdrant.Client, config Config) *Provider
client, _ := qdrant.NewClient(&qdrant.Config{
    Host: "localhost",
    Port: 6334,
})
provider := qdrant.New(client, qdrant.Config{
    Collection: "documents",
})

Config

type Config struct {
    Collection string // Required: Qdrant collection name
}

Behaviors

OperationImplementation
UpsertPoints Upsert
GetPoints Get
DeletePoints Delete
SearchPoints Search
QueryPoints Search with Filter
FilterPoints Scroll with Filter
ListPoints Scroll

Features

FeatureSupport
Filter operatorsAll
ID handlingString → uint64 (FNV-1a hash)
DistanceConfigured at collection level

Error Mapping

Qdrant ErrorGrub Error
Point not foundErrNotFound

Notes

  • String IDs are hashed to uint64 using FNV-1a
  • Original string ID stored in payload
  • Collection must exist before use

Pinecone

import "github.com/zoobz-io/grub/pinecone"

Constructor

func New(conn *pinecone.IndexConnection, config Config) *Provider
client, _ := pinecone.NewClient(pinecone.NewClientParams{
    ApiKey: os.Getenv("PINECONE_API_KEY"),
})
indexConn, _ := client.Index(pinecone.NewIndexConnParams{
    Host: "your-index.svc.environment.pinecone.io",
})
provider := pinecone.New(indexConn, pinecone.Config{
    Namespace: "default",
})

Config

type Config struct {
    Namespace string // Optional: Pinecone namespace
}

Behaviors

OperationImplementation
UpsertUpsert
GetFetch
DeleteDelete
SearchQuery with TopK
QueryQuery with metadata filter
FilterNot supported (returns ErrFilterNotSupported)
ListListVectors

Features

FeatureSupport
Filter operatorsLimited (see below)
ID handlingNative string
Managed serviceYes

Filter Operator Support

OperatorSupport
Eq
Ne
In
Nin
Gt/Gte/Lt/Lte
Like
Contains

Unsupported operators return ErrOperatorNotSupported.

Error Mapping

Pinecone ErrorGrub Error
Vector not foundErrNotFound

Milvus

import "github.com/zoobz-io/grub/milvus"

Constructor

func New(client client.Client, config Config) *Provider
milvusClient, _ := client.NewClient(ctx, client.Config{
    Address: "localhost:19530",
})
provider := milvus.New(milvusClient, milvus.Config{
    Collection:    "documents",
    IDField:       "id",
    VectorField:   "embedding",
    MetadataField: "metadata",
})

Config

type Config struct {
    Collection    string // Required: Milvus collection name
    IDField       string // ID field name (default: "id")
    VectorField   string // Vector field name (default: "embedding")
    MetadataField string // Metadata field name (default: "metadata")
}

Behaviors

OperationImplementation
UpsertInsert with delete-if-exists
GetQuery by ID
DeleteDelete by ID
SearchSearch with expression
QuerySearch with translated filter
FilterQuery with expression
ListQuery all IDs

Features

FeatureSupport
Filter operatorsAll
ID handlingNative string
Configurable fieldsYes

Error Mapping

Milvus ErrorGrub Error
Entity not foundErrNotFound

Notes

  • Collection must exist with appropriate schema
  • Uses Milvus expression language for filters
  • Requires collection to be loaded

Weaviate

import "github.com/zoobz-io/grub/weaviate"

Constructor

func New(client *weaviate.Client, config Config) *Provider
cfg := weaviate.Config{
    Host:   "localhost:8080",
    Scheme: "http",
}
client, _ := weaviate.NewClient(cfg)
provider := weaviate.New(client, weaviate.Config{
    Class:      "Document",
    Properties: []string{"category", "score", "tags"},
})

Config

type Config struct {
    Class      string   // Required: Weaviate class name
    Properties []string // Metadata property names to retrieve in searches
}

Behaviors

OperationImplementation
UpsertData Creator/Updater
GetData ObjectsGetter
DeleteData Deleter
SearchGraphQL NearVector
QueryGraphQL with Where filter
FilterGraphQL Get with Where filter
ListGraphQL Get

Features

FeatureSupport
Filter operatorsAll
ID handlingString → deterministic UUID (SHA1)
GraphQL queriesYes
Properties configRequired for metadata

Error Mapping

Weaviate ErrorGrub Error
404 / not foundErrNotFound

Notes

  • String IDs converted to deterministic UUIDs via SHA1
  • Original string ID stored in _grub_id property
  • Properties must be configured to retrieve metadata in search results
  • Class/schema must exist before use
  • Uses GraphQL for search operations