sdb: nt.web.ve/go/sdb/pkg/sdb Index | Examples | Files

package sdb

import "nt.web.ve/go/sdb/pkg/sdb"

Package sdb provides a simple and embeddable database with full text search support.

Code:

package main

import (
    "errors"
    "fmt"
    "io/ioutil"

    "github.com/blevesearch/bleve"
    "github.com/blevesearch/bleve/analysis/analyzer/keyword"
    "nt.web.ve/go/sdb/pkg/sdb"
)

type Car struct {
    ID    int
    Brand string
    Model string
}

type Person struct {
    ID, Name string
    Email    string
    Alive    bool
    Numbers  []int
    Car      Car
    Family   []Person

    Data map[string]interface{}

    Doctype string // Search index document type.
}

var p = Person{
    ID:    "ntrrg",
    Name:  "Miguel Angel Rivera Notararigo",
    Email: "ntrrg@example.com",
    Alive: true,

    Numbers: []int{11, 2, 0},

    Car: Car{
        ID:    1,
        Brand: "Toyota",
        Model: "Corolla Araya",
    },

    Family: []Person{
        {ID: "alirio", Name: "Alirio Rivera"},
        {ID: "assdro", Name: "Alessandro Notararigo"},
    },

    Data: map[string]interface{}{
        "anime": []string{
            "One Piece",
            "Fullmetal Alchemist",
            "Fate",
            "Hellsing",
            "Naruto",
            "Dragon Ball",
        },
    },

    Doctype: "people",
}

func main() {
    dir, err := ioutil.TempDir("", "sdb")
    if err != nil {
        panic(err)
    }

    opts := sdb.DefaultOptions(dir)

    // Advanced document mapping

    keywordField := bleve.NewTextFieldMapping()
    keywordField.Analyzer = keyword.Name

    peopleMapping := bleve.NewDocumentMapping()
    peopleMapping.AddFieldMappingsAt("Doctype", keywordField)
    // Without this, 'rrg' would match with 'ntrrg', 'atrrg', etc...
    peopleMapping.AddFieldMappingsAt("ID", keywordField)
    peopleMapping.AddFieldMappingsAt("Email", keywordField)
    // Without this, boolean fields couldn't be compared with 'true' of 'false'.
    peopleMapping.AddFieldMappingsAt("Alive", keywordField)

    opts.Bleve.DocMappings["people"] = peopleMapping

    db, err := sdb.OpenWith(opts)
    if err != nil {
        panic(err)
    }

    // If no advanced options are needed, all the previous lines could be
    // replaced by:
    //
    //   db, err := sdb.Open("/path/to/database")
    //   if err != nil {
    //     panic(err)
    //   }

    defer db.Close()

    fmt.Printf("Initial -> %s: %s\n", p.ID, p.Name)

    writeData(db)
    getData(db)
    deleteData(db)

}

func writeData(db *sdb.DB) {
    tx := db.NewTx(sdb.RW)
    defer tx.Discard()

    if err := tx.Set([]byte(p.ID), &p); err != nil {
        panic(err)
    }

    if err := tx.Commit(); err != nil {
        panic(err)
    }
}

func getData(db *sdb.DB) {
    tx := db.NewTx(sdb.RW)
    defer tx.Discard()

    p2 := Person{}
    if err := tx.Get([]byte(p.ID), &p2); err != nil {
        panic(err)
    }

    fmt.Printf("Get -> %s: %s\n", p2.ID, p2.Name)

    q := `Data.anime:"One Piece"`

    keys, err := tx.Find(q)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Find -> (%s): %q\n", q, keys)

    q = "Email:example.com"

    keys, err = tx.Find(q) // Any document with "example.com" as email.
    if err != nil {
        panic(err)
    }

    fmt.Printf("Find -> (%s): %q\n", q, keys)

    prefix := []byte("nt")
    keys = tx.Prefix(prefix) // Any key starting with "nt".
    fmt.Printf("Prefix -> (%s): %q\n", prefix, keys)
}

func deleteData(db *sdb.DB) {
    tx := db.NewTx(sdb.RW)
    defer tx.Discard()

    if err := tx.Delete([]byte(p.ID)); err != nil {
        panic(err)
    }

    p3 := Person{}
    if err := tx.Get([]byte(p.ID), &p3); errors.Is(err, sdb.ErrKeyNotFound) {
        p3.ID = p.ID
        p3.Name = "Not found"
    } else if err != nil {
        panic(err)
    }

    if err := tx.Commit(); err != nil {
        panic(err)
    }

    fmt.Printf("Delete -> %s: %s\n", p3.ID, p3.Name)
}

Index

Examples

Package Files

backup.go doc.go errors.go options.go sdb.go tx.go

Constants

const (
    InMemory       = ""
    DatabaseDir    = "database"
    SearchIndexDir = "search-index"
)
const (
    RW  = true
    RO  = false
)

Variables

var (
    ErrValMustBePointer = errors.New("can't encode data, must be a pointer")

    ErrKeyNotFound = badgerError(badger.ErrKeyNotFound)
    ErrTxnTooBig   = badgerError(badger.ErrTxnTooBig)
)

func IsBadgerError Uses

func IsBadgerError(err error) bool

IsBadgerError returns true if the given error is from Badger.

func IsBleveError Uses

func IsBleveError(err error) bool

IsBleveError returns true if the given error is from Bleve.

type BleveOptions Uses

type BleveOptions struct {
    Dir          string
    DoctypeField string
    DocMappings  map[string]*mapping.DocumentMapping
}

type DB Uses

type DB struct {
    // contains filtered or unexported fields
}

DB is a database object which provides database management methods, for data management see Tx.

func Open Uses

func Open(dir string) (*DB, error)

Open initializes a database in the given directory.

func OpenWith Uses

func OpenWith(opts Options) (db *DB, err error)

OpenWith initializes a database with the given options.

func (*DB) Close Uses

func (db *DB) Close() error

Close terminates the database.

func (*DB) NewTx Uses

func (db *DB) NewTx(rw bool) *Tx

NewTx creates a database transaction. If rw is false, the new transaction will be read-only.

func (*DB) ReloadIndex Uses

func (db *DB) ReloadIndex(f DecoderFunc) error

ReloadIndex recreates the search index, it takes a decoder function as argument, this is necessary since it is not possible to decode one type into another.

type DecoderFunc Uses

type DecoderFunc func(tx *Tx, key []byte) (interface{}, error)

Code:

db, err := sdb.Open(sdb.InMemory)
if err != nil {
    panic(err)
}

defer db.Close()

f := func(tx *sdb.Tx, key []byte) (interface{}, error) {
    switch {
    case bytes.HasPrefix(key, []byte("strings-")):
        var v string

        if errGet := tx.Get(key, &v); err != nil {
            return nil, errGet
        }

        return v, nil
    case bytes.HasPrefix(key, []byte("numbers-")):
        var v int

        if errGet := tx.Get(key, &v); err != nil {
            return nil, errGet
        }

        return v, nil
    }

    return nil, fmt.Errorf("unknown type")
}

if errReload := db.ReloadIndex(f); err != nil {
    panic(errReload)
}

type Options Uses

type Options struct {
    // Database location.
    Dir string

    Badger badger.Options
    Bleve  BleveOptions

    BufferPoolSize     int  // Amount of buffers.
    BufferPoolMaxBytes int  // Bytes limit per buffer.
    BufferPoolFill     bool // Fill up the pool at DB creation.

    Logger *log.Logger
}

Options are parameters for initializing a database.

func DefaultOptions Uses

func DefaultOptions(dir string) Options

DefaultOptions returns commonly used options for creating a database.

func MemoryOptions Uses

func MemoryOptions() (Options, error)

MemoryOptions returns options tweaked for running a DB instance in memory.

type Tx Uses

type Tx struct {
    // contains filtered or unexported fields
}

Tx is a transaction object which provides data management methods. The search index doesn't support transactions yet, so indexing operations just take effect after committing the transaction.

func (*Tx) Commit Uses

func (tx *Tx) Commit() error

Commit writes the transaction operations to the database. If a Bleve error is returned, the search index should be reloaded (see DB.ReloadIndex), keep the amount of operations per transaction low to avoid this.

func (*Tx) Delete Uses

func (tx *Tx) Delete(key []byte) error

Delete deletes the given key. This operation happens in memory, it will be written to the database once Commit is called.

func (*Tx) Discard Uses

func (tx *Tx) Discard()

Discard drops all the pending modifications and set the transactions as discarded.

func (*Tx) Find Uses

func (tx *Tx) Find(q string, sort ...string) ([][]byte, error)

Find fetches the keys from the values that satisfies the given constraints. See http://blevesearch.com/docs/Query-String-Query/ for more info about the the query language syntax. sort is a list of field names used for sorting, any field prefixed by a hyphen (-) will user reverse order.

func (*Tx) Get Uses

func (tx *Tx) Get(key []byte, v interface{}) error

Get reads the value from the given key and decodes it into v. v must be a pointer.

func (*Tx) Prefix Uses

func (tx *Tx) Prefix(prefix []byte) [][]byte

Prefix fetches all the keys from the database with the given prefix.

func (*Tx) Set Uses

func (tx *Tx) Set(key []byte, v interface{}) (err error)

Set set v as value of the given key. This operation happens in memory, it will be written to the database once Commit is called. v must be a pointer.

Package sdb imports 14 packages (graph). Updated 2019-11-28. Refresh now. Tools for package owners.