Categorygithub.com/fobilow/gitdb/v2
modulepackage
2.0.1
Repository: https://github.com/fobilow/gitdb.git
Documentation: pkg.go.dev

# README

GitDB

Go Report Card Coverage Build Status Travis Godoc Releases LICENSE

What is GitDB?

GitDB is not a binary. It’s a library!

GitDB is a decentralized document database written in Go. It provides database-like functionalities via strictly defined interfaces.

GitDB allows developers to create Models of objects in their application which implement a Model Interface that can access it's persistence features. This allows GitDB to work with these objects in database operations.

Why GitDB - motivation behind project?

  • A need for a database that was quick and simple to set up
  • A need for a database that was decentralized and each participating client in a system can store their data independent of other clients.

Features

  • Decentralized
  • Document store
  • Embedded into your go application
  • Encryption (encrypt on write, decrypt on read)
  • Record locking.
  • Simple Indexing System
  • Transactions
  • Web UI

Project versioning

GitDB uses semantic versioning. API should not change between patch and minor releases. New minor versions may add additional features to the API.

Table of Contents

Getting Started

Installing

To start using GitDB, install Go and run go get:

$ go get github.com/fobilow/gitdb/v2

Configuration

Below are configuration options provided by GitDB

NameDescriptionTypeRequiredDefault
DbPathPath on computer where you want GitDB to create/clone your databasestringYN/A
ConnectionNameUnique name for gitdb connection. Use this when opening multiple GitDB connectionsstringN"default"
OnlineRemoteURL for remote git server you want GitDB to sync with e.g [email protected]:user/db.git or https://github.com/user/db.git.

Note: GitDB automatically generates ssh keys for every database and will automatically use this key to sync with the OnlineRemote, therefore ensure that the generated keys are added to this git server. The ssh keys can be found at Config.DbPath/.gitdb/.ssh

stringN""
SyncIntervalThis controls how often you want GitDB to sync with the online remotetime.Duration.N5s
EncryptionKey16,24, or 32 byte string used to provide AES encryption for Models that implement ShouldEncryptstringN""
UserThis specifies the user connected to the Gitdb and will be used to commit all changes to the databasegitdb.UserNghost <ghost@local>
UIPortUse this option to change the default port which GitDB uses to serve it's web user interfaceintN4120
FactoryFor backward compatibity with v1. In v1 GitDB needed a factory method to be able construct concrete Model for certain database operations. This has now been dropped in v2 func(dataset string) gitdb.ModelNnil

You can configure GitDB either using the constructor or constructing it yourself

cfg := gitdb.NewConfig(path)
//or
cfg := gitdb.Config{
  DbPath: path
}

Importing GitDB

To use GitDB as an embedded document store, import as:

import "github.com/fobilow/gitdb/v2"

cfg := gitdb.NewConfig(path)
db, err := gitdb.Open(cfg)
if err != nil {
  log.Fatal(err)
}
defer db.Close()

Opening a database

package main

import (
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main() {
  
  cfg := gitdb.NewConfig("/tmp/data")
  // Open will create or clone down a git repo 
  // in configured path if it does not exist.
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  ...
}

Models

A Model is a struct that represents a record in GitDB. GitDB only works with models that implement the gidb.Model interface

gitdb.TimeStampedModel is a simple struct that allows you to easily add CreatedAt and UpdatedAt to all the Models in your application and will automatically time stamp them before persisting to GitDB. You can write your own base Models to embed common fields across your application Models

type BankAccount struct {
  //TimeStampedModel will add CreatedAt and UpdatedAt fields this Model
  gitdb.TimeStampedModel 
  AccountType         string
  AccountNo           string
  Currency            string
  Name                string
}

func (b *BankAccount) GetSchema() *gitdb.Schema {
  //Dataset Name
  name := "Accounts"
  //Block ID
  block := b.CreatedAt.Format("200601")
  //Record ID
  record := b.AccountNo

  //Indexes speed up searching
  indexes := make(map[string]interface{})
  indexes["AccountType"] = b.AccountType
 
  return gitdb.NewSchema(name, block, record, indexes)
}

func (b *BankAccount) Validate() error            { return nil }
func (b *BankAccount) IsLockable() bool           { return false }
func (b *BankAccount) ShouldEncrypt() bool        { return false }
func (b *BankAccount) GetLockFileNames() []string { return []string{} }

...
  

Inserting/Updating a record

package main

import (
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main(){
  cfg := gitdb.NewConfig("/tmp/data")
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  //populate model
  account := &BankAccount()
  account.AccountNo = "0123456789"
  account.AccountType = "Savings"
  account.Currency = "GBP"
  account.Name = "Foo Bar"

  err = db.Insert(account)
  if err != nil {
    log.Println(err)
  }

  //get account id
  log.Println(gitdb.Id(account))

  //update account name
  account.Name = "Bar Foo"
  err = db.Insert(account)
  if err != nil {
    log.Println(err)
  }
}

Fetching a single record

package main
import (
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main(){
  cfg := gitdb.NewConfig("/tmp/data")
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  //model to passed to Get to store result 
  var account BankAccount()
  err = db.Get("Accounts/202003/0123456789", &account)
  if err != nil {
    log.Println(err)
  }
}

Fetching all records in a dataset

package main

import (
  "fmt"
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main(){
  cfg := gitdb.NewConfig("/tmp/data")
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  records, err := db.Fetch("Accounts")
  if err != nil {
    log.Print(err)
    return
  }

  accounts := []*BankAccount{}
  for _, r := range records {
    b := &BankAccount{}
    r.Hydrate(b)
    accounts = append(accounts, b)
    log.Print(fmt.Sprintf("%s-%s", gitdb.ID(b), b.AccountNo))
  }
}

Deleting a record

package main

import (
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main(){
  cfg := gitdb.NewConfig("/tmp/data")
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  err := db.Delete("Accounts/202003/0123456789")
  if err != nil {
    log.Print(err)
  }
}

Search for records

package main

import (
  "fmt"
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main(){
  cfg := gitdb.NewConfig("/tmp/data")
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  //Find all records that have savings account type
  searchParam := &db.SearchParam{Index: "AccountType", Value: "Savings"}
  records, err := dbconn.Search("Accounts", []*db.SearchParam{searchParam}, gitdb.SearchEquals)
  if err != nil {
    log.Println(err.Error())
    return
  } 

  accounts := []*BankAccount{}
  for _, r := range records {
    b := &BankAccount{}
    r.Hydrate(b)
    accounts = append(accounts, b)
    log.Print(fmt.Sprintf("%s-%s", b.ID, b.CreatedAt))
  }
}

Transactions

package main

import (
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main() {
  cfg := gitdb.NewConfig("/tmp/data")
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  func accountUpgradeFuncOne() error { println("accountUpgradeFuncOne..."); return nil }
  func accountUpgradeFuncTwo() error { println("accountUpgradeFuncTwo..."); return errors.New("accountUpgradeFuncTwo failed") }
  func accountUpgradeFuncThree() error { println("accountUpgradeFuncThree"); return nil }

  tx := db.StartTransaction("AccountUpgrade")
  tx.AddOperation(accountUpgradeFuncOne)
  tx.AddOperation(accountUpgradeFuncTwo)
  tx.AddOperation(accountUpgradeFuncThree)
  terr := tx.Commit()
  if terr != nil {
    log.Print(terr)
  }
}

Encryption

GitDB suppports AES encryption and is done on a Model level, which means you can have a database with different Models where some are encrypted and others are not. To encrypt your data, your Model must implement ShouldEncrypt() to return true and you must set gitdb.Config.EncryptionKey. For maximum security set this key to a 32 byte string to select AES-256

package main

import (
  "log"
  "github.com/fobilow/gitdb/v2"
)

func main(){
  cfg := gitdb.NewConfig("/tmp/data")
  cfg.EncryptionKey = "a_32_bytes_string_for_AES-256"
  db, err := gitdb.Open(cfg)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  //populate model
  account := &BankAccount()
  account.AccountNo = "0123456789"
  account.AccountType = "Savings"
  account.Currency = "GBP"
  account.Name = "Foo Bar"

  //Insert will encrypt the account
  err = db.Insert(account)
  if err != nil {
    log.Println(err)
  }

  //Get will automatically decrypt account
  var account BankAccount()
  err = db.Get("Accounts/202003/0123456789", &account)
  if err != nil {
    log.Println(err)
  }
}

Resources

For more information on getting started with Gitdb, check out the following articles:

Caveats & Limitations

It's important to pick the right tool for the job and GitDB is no exception. Here are a few things to note when evaluating and using GitDB:

  • GitDB is good for systems where data producers are indpendent.
  • GitDB currently depends on the git binary to work

Reading the Source

GitDB is a relatively small code base (<5KLOC) for an embedded, distributed, document database so it can be a good starting point for people interested in how databases work.

The best places to start are the main entry points into GitDB:

  • Open() - Initializes the reference to the database. It's responsible for creating the database if it doesn't exist and pulling down existing database if an online remote is specified.

If you have additional notes that could be helpful for others, please submit them via pull request.

# Packages

No description provided by the author
go:generate gitdb embed-ui -o ./ui_gitdb.go.

# Functions

AutoBlock automatically generates block id for a given Model depending on a BlockMethod.
Conn returns the last connection started by Open(*Config) if you opened more than one connection use GetConn(name) instead.
GetConn returns a specific gitdb connection by name.
ID returns the id of a given Model.
Indexes returns the index map of a given Model.
NewConfig constructs a *Config.
NewSchema constructs a *Schema.
NewUser constructs a *DbUser.
Open opens a connection to GitDB.
ParseID parses a record id and returns it's metadata.
SetLogger sets Logger.
SetLogLevel sets log level.
UI provides an API to run UI server from outside this package.

# Constants

LogLevelError - logs only errors.
LogLevelInfo - logs info, warining and errors.
LogLevelNone - log nothing.
LogLevelTest - logs only debug messages.
LogLevelWarning - logs warning and errors.
RecVersion of gitdb.
SearchContains will search index for records whose values contain SearchParam.Value.
SearchEndsWith will search index for records whose values ends with SearchParam.Value.
SearchEquals will search index for records whose values equal SearchParam.Value.
SearchStartsWith will search index for records whose values start with SearchParam.Value.

# Variables

BlockByCount generates a new block when the number of records has reached a specified count.
BlockBySize generates a new block when current block has reached a specified size.

# Structs

Config represents configuration options for GitDB.
Schema holds functions for generating a model id.
SearchParam represents search parameters against GitDB index.
TimeStampedModel provides time stamp fields.
User represents the user currently connected to the databaseand will be used to identify who made changes to it.

# Interfaces

GitDb interface defines all export funcs an implementation must have.
GUI interface.
Model interface describes methods GitDB supports.

# Type aliases

BlockMethod type of method to use with AutoBlock.
LogLevel is used to set verbosity of GitDB.
SearchMode defines how gitdb should search with SearchParam.