FluentKV

module
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2023 License: MIT

README

Banner

GoDoc Go Report Card

Purpose a fluent toolkit for using a KV database.

System Architecture

Interface and Abstract Struct Implementation

The interface IRelationalDB defines a set of raw operations that must be implemented. It also holds some additional simpler operations already realized but they can be overridden if required. For further details, refer to the file reldb/relational.go.

The abstract struct AbstractRelDB extends IRelationalDB. It pre-implements the key filler system and all other operations using raw operations provided by the implementation. Check the file reldb/abstract.go for a comprehensive understanding.

IObject Interface and ObjWrapper Struct

The IObject interface contains operations essential for this architecture. These operations, such as Equals, Hash, are primarily implemented with the DBObject abstraction but the TableName function needs explicit implementation. This function generates a key corresponding to data.

The ObjWrapper struct is a helper to store a value along with its unique id. It is used extensively across this toolkit to bind the IObject with the database or to return the value with its corresponding id.

Implementation

At present, there is one main implementation for a KV Database:

Collection

A straightforward way of performing operations on a list of items provided by a TableName.

In SQL, certain operations are performed on a list of rows, usually fetched using the FROM command. The Collection's constructor accepts a DBObject type to build the subsequent objects array from the TableName.

Several functions can be executed effortlessly using Go code and loops. Therefore, Collection doesn’t furnish all SQL operations: You can conveniently retrieve the underlying array via the GetArray() method and apply your logic on it.

Collection provides:

  • Distinct: Removes all duplicates.
  • Sort: Accepts a sorting function and arranges the collection accordingly.
  • Filter: Accepts a predicate function and excludes all items that fail the condition.
  • Where: Operates like a JOIN but uses the link concept of this library.

[TODO] Handlers

Register functions that will be executed on some event like Insert, Delete or Update.

Usage

This section explain basic usage with preparation of type and, first of usage and more advanced use case. You can also see the tests sources for additional information.

Prepare your types

In first time, you can declare a type like this:

type Person struct {
    DBObject // Note this, is for the default implementation.
    Firstname  string
    Lastname  string
    Age int
}

IObject has four operations (Equals, Hash, ToString, TableName), DBObject implement Equals and Hash. You can override this implementation, but you need to implement ToString and TableName. You can simply use the helpers like this:

func (t Person) ToString() string  { return reldb.ToString(t) }

func (t Person) TableName() string { return reldb.NameOfStruct[Person]() }

To simplify the construction of IObject is recommended to make a constructor (it can internally affect the DBObject with the new instance created):

func NewPerson(firstname string, lastname string, age int) Person {
    person := Person{Firstname: firstname, Lastname: lastname, Age: age}
    person.IObject = person // Mandatory (here or manualy before using). 

    return person
}

In last time, you need to register your type to Gob (the binary serializer used) like this (simply do it before use):

gob.Register(Person{})

Basic operations

// Initialize db
AutoKeyBuffer = 10
db, _ := NewBadgerDB("data")
  • Insert, Get, Set: There is the basic operation to store and use data from the db.

    person := NewPerson("Foo", "Bar", 42)
    personWrapped = Insert(db, person) // Insert a DBObject in db. 
    // This operation return an ObjWrapper[Person]
    
    // Get the Person object from the id:
    valueWrp := Get[Person](db, personWrapped.ID)
    
    // Change the value at the index personWrapped.ID:
    Set(db, NewPerson("Bar", "Foo", 1), personWrapped.ID)
    
  • Update: Allows you to edit the saved object without recreating it. Useful if the object has many fields and you want to edit only one for example.

    Update(db, personWrapped.ID, func (person *Person) {
        person.Age = 12
    })
    
  • Exist, Count:

    Count[Person](db)                   // Count = 1
    Exist[Person](db, personWrapped.ID) // Exist = true
    
  • Link, LinkNew, UnlinkAll, RemoveLink, RemoveAllLink: Link concept allows to retrieve an object of another table linked to the current one.

    // It supposed we have a struct Address(Street string, City string) for example.
    
    addressWrp := Insert(db, NewAddress("", ""))
    Link(addressWrp, true, personWrapped)
    // We can do this instead of:
    // addressWrp := LinkNew(NewAddress("", ""), true, personWrapped)
    
    AllFromLink[Person, Address](personWrapped) // Result is an array with only addressWrp.
    
    RemoveLink(addressWrp, personWrapped)
    
  • Delete, DeepDelete:

    addressWrp := Insert(db, NewAddress("", ""))
    Link(addressWrp, true, personWrapped)
    
    DeepDeleteWrp[Address](addressWrp) // Delete addressWrp and personWrapped.
    
    // Or for delete only addressWrp:
    // DeleteWrp[Address](addressWrp) 
    
  • FindFirst, FindAll:

    // Prepare a list of persons.
    persons := []Person{
        NewPerson("Jean", "Smith", 21),
        NewPerson("Richard", "Smith", 25),
        NewPerson("James", "Smith", 32),
    }
    
    // Fill the db with this new person.
    for _, person := range persons {
        Insert(db, person)
    }
    
    // Search the first person 25 years old (Richard):
    result := FindFirst(db, func(id string, person *Person) bool {
        return person.Age == 25
    })
    
    // Or search all persons more than 22 years old (Richard, James):
    results := FindFirst(db, func(id string, person *Person) bool {
        return person.Age > 22
    })
    
  • Foreach, Visit:

    personWrp = Insert(db, NewPerson("Foo", "Bar", 42))
    addressWrp := Insert(db, NewAddress("", ""))
    
    Link(addressWrp, true, personWrp)
    
    // Foreach provide a way to perform some operation on a copy of each value of a table:
    Foreach(db, func(id string, value *Person) {
        // Use `id` and `value` here.
    })
    
    // Visit permit to retreive all ids of object linked to another one:
    ids := VisitWrp[Address, Person](addressWrp) 
    // len(ids) == 1 ; ids[0] == personWrp.ID
    

[TODO] More advanced operations

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL