ds

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 9, 2020 License: MIT Imports: 12 Imported by: 1

README

DS

Go Report Card Godoc Releases LICENSE

Package ds (short for "data store") is a key-value store with hash indexes. It allows for rudementary but lightning fast retrevial of grouped or relevant data without having to iterate over all objects in the store.

Usage & Examples

Examples can be found on the documentation for the library

Documentation

Overview

Package ds (short for "data store") is a key-value store with hash indexes. It allows for rudementary but lightning fast retrevial of grouped or relevant data without having to iterate over all objects in the store.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Name            string
	TypeOf          string
	PrimaryKey      string
	Indexes         []string
	Uniques         []string
	LastInsertIndex uint64
}

Config describes ds table configuration

type GetOptions

type GetOptions struct {
	// Should the results be sorted. Does nothing for unsorted tables
	Sorted bool
	// If results are to be sorted, should they be from most recent to oldest (true) or invese (false)
	Ascending bool
	// The maximum number of entries to return. 0 means unlimited
	Max int
}

GetOptions describes options for getting entries from a DS table

type MigrateParams

type MigrateParams struct {
	// TablePath the path to the existing table
	TablePath string
	// NewPath the path for the new table. This can be the same as the old table.
	NewPath string
	// OldType the old type (current type of the table)
	OldType interface{}
	// NewType the new type. This can be the same as the OldType.
	NewType interface{}
	// DisableSorting if the current table is sorted, set this to true to disable sorting
	// Note: This is irreversible!
	DisableSorting bool
	// MigrateObject method called for each entry in the table. Return a new type or error.
	// migration is halted if an error is returned.
	// Return (nil, nil) and the entry will be skipped from migration.
	MigrateObject func(o interface{}) (interface{}, error)
}

MigrateParams describes the parameters to perform a DS table migration. All fields are required.

type MigrationResults

type MigrationResults struct {
	// Success was the migration successful
	Success bool
	// Error if unsuccessful, this will be the error that caused the failure
	Error error
	// EntriesMigrated the number of entries migrated
	EntriesMigrated uint
	// EntriesSkipped the number of entries skipped
	EntriesSkipped uint
}

MigrationResults describes results from a migration

func Migrate

func Migrate(params MigrateParams) (results MigrationResults)

Migrate will migrate a DS table from one object type to another. The migration process appends "_backup" to the current tables filename and does not update it in any way. A new table file is created with the migrated entries and indexes.

Example
package main

import (
	"fmt"

	"github.com/ecnepsnai/ds"
)

func main() {
	// Define a struct that maps to the current type used in the table
	type oldType struct {
		Username  string `ds:"primary"`
		Email     string `ds:"unique"`
		FirstName string
		LastName  string
	}

	// Define your new struct
	type newType struct {
		Username string `ds:"primary"`
		Email    string `ds:"unique"`
		Name     string
	}

	// In this example, we're merging the "FirstName" and "LastName" fields of the User object to
	// just a single "Name" field
	result := ds.Migrate(ds.MigrateParams{
		TablePath: "/path/to/table.db",
		NewPath:   "/path/to/table.db", // You can specify the same path, or a new one if you want
		OldType:   oldType{},
		NewType:   newType{}, // NewType can be the same as the old type if you aren't changing the struct
		MigrateObject: func(o interface{}) (interface{}, error) {
			old := o.(oldType)
			// Within the MigrateObject function you can:
			// 1. Return a object of the NewType (specified in the MigrateParams)
			// 2. Return an error and the migration will abort
			// 3. Return nil and this entry will be skipped
			return newType{
				Username: old.Username,
				Email:    old.Email,
				Name:     old.FirstName + " " + old.LastName,
			}, nil
		},
	})
	if !result.Success {
		// Migration failed.
		panic(result.Error)
	}

	fmt.Printf("Migration successful. Entries migrated: %d, skipped: %d\n", result.EntriesMigrated, result.EntriesSkipped)
}
Output:

type Options

type Options struct {
	// DisableSorting disable all sorting features. This will make tables smaller, and inserts/removes/deletes faster.
	DisableSorting bool
	// contains filtered or unexported fields
}

Options describes options for DS tables. Once set, these cannot be changed.

type Table

type Table struct {
	Name string
	// contains filtered or unexported fields
}

Table describes a ds table. A table is mapped to a single registered object type and contains both the data and the indexes.

func Register

func Register(o interface{}, filePath string, options *Options) (*Table, error)

Register will register an instance of a struct with ds, creating a table (or opening an existing table) for this type at the specified file path.

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	type User struct {
		// Primary fields represent the primary key of the object. Your object must have exactly one primary field
		// and its value is unique
		Username string `ds:"primary"`
		// Unique fields function just like primary fields except any field (other than the primary field) can be unique
		Email string `ds:"unique"`
		// Index fields represent fields where objects with identical values are grouped together so they can be fetched
		// quickly later
		Enabled bool `ds:"index"`
		// Fields with no ds tag are saved, but you can't fetch based on their value, and can have duplicate values
		// between entries
		Password string
	}

	tablePath := "user.db"

	table, err := ds.Register(User{}, tablePath, nil)
	if err != nil {
		panic(err)
	}

	// Don't forget to close your table when you're finished
	table.Close()
}
Output:

func (*Table) Add

func (table *Table) Add(o interface{}) error

Add will add a new object to the table. o must the the same type that was used to register the table and cannot be a pointer.

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	type User struct {
		Username string `ds:"primary"`
		Password string
		Email    string `ds:"unique"`
		Enabled  bool   `ds:"index"`
	}

	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	newUser := User{
		Username: "ian",
		Password: "hunter2",
		Email:    "email@domain",
		Enabled:  true,
	}

	if err := table.Add(newUser); err != nil {
		panic(err)
	}
}
Output:

func (*Table) Close

func (table *Table) Close()

Close will close the table. This will not panic if the table has not been opened or already been closed.

func (*Table) Delete

func (table *Table) Delete(o interface{}) error

Delete will delete the provided object and clean indexes

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	type User struct {
		Username string `ds:"primary"`
		Password string
		Email    string `ds:"unique"`
		Enabled  bool   `ds:"index"`
	}

	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	deleteUser := User{
		Username: "ian",
		Password: "hunter2",
		Email:    "email@domain",
		Enabled:  true,
	}

	// Delete the object
	if err := table.Delete(deleteUser); err != nil {
		panic(err)
	}
}
Output:

func (*Table) DeleteAll

func (table *Table) DeleteAll() error

DeleteAll delete all objects from the table

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	// Delete all objects
	if err := table.DeleteAll(); err != nil {
		panic(err)
	}
}
Output:

func (*Table) DeleteAllIndex

func (table *Table) DeleteAllIndex(fieldName string, value interface{}) error

DeleteAllIndex will delete all objects matching the given indexed fields value

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	// Delete all objects with the following indexed fields value
	if err := table.DeleteAllIndex("Enabled", false); err != nil {
		panic(err)
	}
}
Output:

func (*Table) DeletePrimaryKey

func (table *Table) DeletePrimaryKey(o interface{}) error

DeletePrimaryKey will delete the object with the associated primary key and clean indexes

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	// Delete an object by its primary key
	if err := table.DeletePrimaryKey("ian"); err != nil {
		panic(err)
	}
}
Output:

func (*Table) DeleteUnique

func (table *Table) DeleteUnique(field string, o interface{}) error

DeleteUnique will delete the object with the associated unique value and clean indexes

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	// Delete an object by a unique fields value
	if err := table.DeleteUnique("Email", "user@domain"); err != nil {
		panic(err)
	}
}
Output:

func (*Table) Get

func (table *Table) Get(primaryKey interface{}) (interface{}, error)

Get will get a single entry by its primary key. Returns (nil, nil) if nothing found.

Example
package main

import (
	"fmt"

	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	type User struct {
		Username string `ds:"primary"`
	}

	object, err := table.Get("ian")
	if err != nil {
		panic(err)
	}
	if object == nil {
		// No object with that primary key found
	}

	user, ok := object.(User)
	if !ok {
		// The object wasn't a `User`
	}

	fmt.Printf("Username: %s\n", user)
}
Output:

func (*Table) GetAll

func (table *Table) GetAll(options *GetOptions) ([]interface{}, error)

GetAll will get all of the entries in the table.

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	type User struct {
		Username string `ds:"primary"`
	}

	// Get only the first 100 users sorted by when they were added
	objects, err := table.GetAll(&ds.GetOptions{
		Sorted:    true,
		Ascending: true,
		Max:       100,
	})
	if err != nil {
		panic(err)
	}
	if objects == nil {
		// No objects were returned
	}

	users := make([]User, len(objects))
	for i, object := range objects {
		user, ok := object.(User)
		if !ok {
			// The object wasn't a `User`
		}
		users[i] = user
	}
}
Output:

func (*Table) GetIndex

func (table *Table) GetIndex(fieldName string, value interface{}, options *GetOptions) ([]interface{}, error)

GetIndex will get multiple entries that contain the same value for the specified indexed field. Result is not ordered. Use GetIndexSorted to return a sorted slice. Returns an empty array if nothing found.

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	type User struct {
		Username string `ds:"primary"`
		Enabled  bool   `ds:"index"`
	}

	// Get all enabled users
	objects, err := table.GetIndex("Enabled", true, nil)
	if err != nil {
		panic(err)
	}
	if objects == nil {
		// No objects were returned
	}

	users := make([]User, len(objects))
	for i, object := range objects {
		user, ok := object.(User)
		if !ok {
			// The object wasn't a `User`
		}
		users[i] = user
	}
}
Output:

func (*Table) GetUnique

func (table *Table) GetUnique(fieldName string, value interface{}) (interface{}, error)

GetUnique will get a single entry based on the value of the provided unique field. Returns (nil, nil) if nothing found.

Example
package main

import (
	"fmt"

	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	type User struct {
		Username string `ds:"primary"`
		Email    string `ds:"unique"`
	}

	// Get the user with the email user@domain
	object, err := table.GetUnique("Email", "user@domain")
	if err != nil {
		panic(err)
	}
	if object == nil {
		// No object with that primary key found
	}

	user, ok := object.(User)
	if !ok {
		// The object wasn't a `User`
	}

	fmt.Printf("Username: %s\n", user)
}
Output:

func (*Table) IsIndexed

func (table *Table) IsIndexed(field string) bool

IsIndexed is the given field indexed

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	type User struct {
		Username string `ds:"primary"`
		Email    string `ds:"email"`
		Enabled  bool   `ds:"index"`
	}

	table.IsIndexed("Username") // returns False
	table.IsIndexed("Enabled")  // returns True
}
Output:

func (*Table) IsUnique

func (table *Table) IsUnique(field string) bool

IsUnique is the given field unique

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	type User struct {
		Username string `ds:"primary"`
		Email    string `ds:"email"`
		Enabled  bool   `ds:"index"`
	}

	table.IsUnique("Username") // returns False
	table.IsUnique("Email")    // returns True
}
Output:

func (*Table) Update

func (table *Table) Update(o interface{}) error

Update will update an existing object in the table. The primary key must match for this object otherwise it will just be inserted as a new object.

Example
package main

import (
	"github.com/ecnepsnai/ds"
)

func main() {
	type User struct {
		Username string `ds:"primary"`
		Password string
		Email    string `ds:"unique"`
		Enabled  bool   `ds:"index"`
	}

	var table *ds.Table // Assumes the table is already registered, see ds.Register for an example

	newUser := User{
		Username: "ian",
		Password: "hunter2",
		Email:    "email@domain",
		Enabled:  true,
	}
	if err := table.Add(newUser); err != nil {
		panic(err)
	}

	newUser.Password = "something else"

	// Update an existing entry (based on the primary key)
	if err := table.Update(newUser); err != nil {
		panic(err)
	}
}
Output:

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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