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 ¶
- type Config
- type GetOptions
- type MigrateParams
- type MigrationResults
- type Options
- type Table
- func (table *Table) Add(o interface{}) error
- func (table *Table) Close()
- func (table *Table) Delete(o interface{}) error
- func (table *Table) DeleteAll() error
- func (table *Table) DeleteAllIndex(fieldName string, value interface{}) error
- func (table *Table) DeletePrimaryKey(o interface{}) error
- func (table *Table) DeleteUnique(field string, o interface{}) error
- func (table *Table) Get(primaryKey interface{}) (interface{}, error)
- func (table *Table) GetAll(options *GetOptions) ([]interface{}, error)
- func (table *Table) GetIndex(fieldName string, value interface{}, options *GetOptions) ([]interface{}, error)
- func (table *Table) GetUnique(fieldName string, value interface{}) (interface{}, error)
- func (table *Table) IsIndexed(field string) bool
- func (table *Table) IsUnique(field string) bool
- func (table *Table) Update(o interface{}) error
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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: