123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- package database
- /*
- ArOZ Online Database Access Module
- author: tobychui
- This is an improved Object oriented base solution to the original
- aroz online database script.
- */
- import (
- "encoding/json"
- "errors"
- "log"
- "sync"
- "github.com/boltdb/bolt"
- )
- type Database struct {
- Db *bolt.DB
- Tables sync.Map
- ReadOnly bool
- }
- func NewDatabase(dbfile string, readOnlyMode bool) (*Database, error) {
- db, err := bolt.Open(dbfile, 0600, nil)
- log.Println("Key-value Database Service Started: " + dbfile)
- tableMap := sync.Map{}
- //Build the table list from database
- err = db.View(func(tx *bolt.Tx) error {
- return tx.ForEach(func(name []byte, _ *bolt.Bucket) error {
- tableMap.Store(string(name), "")
- return nil
- })
- })
- return &Database{
- Db: db,
- Tables: tableMap,
- ReadOnly: readOnlyMode,
- }, err
- }
- /*
- Create / Drop a table
- Usage:
- err := sysdb.NewTable("MyTable")
- err := sysdb.DropTable("MyTable")
- */
- func (d *Database) UpdateReadWriteMode(readOnly bool) {
- d.ReadOnly = readOnly
- }
- //Dump the whole db into a log file
- func (d *Database) Dump(filename string) ([]string, error) {
- results := []string{}
- d.Tables.Range(func(tableName, v interface{}) bool {
- entries, err := d.ListTable(tableName.(string))
- if err != nil {
- log.Println("Reading table " + tableName.(string) + " failed: " + err.Error())
- return false
- }
- for _, keypairs := range entries {
- results = append(results, string(keypairs[0])+":"+string(keypairs[1])+"\n")
- }
- return true
- })
- return results, nil
- }
- //Create a new table
- func (d *Database) NewTable(tableName string) error {
- if d.ReadOnly == true {
- return errors.New("Operation rejected in ReadOnly mode")
- }
- err := d.Db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucketIfNotExists([]byte(tableName))
- if err != nil {
- return err
- }
- return nil
- })
- d.Tables.Store(tableName, "")
- return err
- }
- //Check is table exists
- func (d *Database) TableExists(tableName string) bool {
- if _, ok := d.Tables.Load(tableName); ok {
- return true
- }
- return false
- }
- //Drop the given table
- func (d *Database) DropTable(tableName string) error {
- if d.ReadOnly == true {
- return errors.New("Operation rejected in ReadOnly mode")
- }
- err := d.Db.Update(func(tx *bolt.Tx) error {
- err := tx.DeleteBucket([]byte(tableName))
- if err != nil {
- return err
- }
- return nil
- })
- return err
- }
- /*
- Write to database with given tablename and key. Example Usage:
- type demo struct{
- content string
- }
- thisDemo := demo{
- content: "Hello World",
- }
- err := sysdb.Write("MyTable", "username/message",thisDemo);
- */
- func (d *Database) Write(tableName string, key string, value interface{}) error {
- if d.ReadOnly == true {
- return errors.New("Operation rejected in ReadOnly mode")
- }
- jsonString, err := json.Marshal(value)
- if err != nil {
- return err
- }
- err = d.Db.Update(func(tx *bolt.Tx) error {
- _, err := tx.CreateBucketIfNotExists([]byte(tableName))
- b := tx.Bucket([]byte(tableName))
- err = b.Put([]byte(key), jsonString)
- return err
- })
- return err
- }
- /*
- Read from database and assign the content to a given datatype. Example Usage:
- type demo struct{
- content string
- }
- thisDemo := new(demo)
- err := sysdb.Read("MyTable", "username/message",&thisDemo);
- */
- func (d *Database) Read(tableName string, key string, assignee interface{}) error {
- err := d.Db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(tableName))
- v := b.Get([]byte(key))
- json.Unmarshal(v, &assignee)
- return nil
- })
- return err
- }
- func (d *Database) KeyExists(tableName string, key string) bool {
- resultIsNil := false
- err := d.Db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(tableName))
- v := b.Get([]byte(key))
- if v == nil {
- resultIsNil = true
- }
- return nil
- })
- if err != nil {
- return false
- } else {
- if resultIsNil {
- return false
- } else {
- return true
- }
- }
- }
- /*
- Delete a value from the database table given tablename and key
- err := sysdb.Delete("MyTable", "username/message");
- */
- func (d *Database) Delete(tableName string, key string) error {
- if d.ReadOnly == true {
- return errors.New("Operation rejected in ReadOnly mode")
- }
- err := d.Db.Update(func(tx *bolt.Tx) error {
- tx.Bucket([]byte(tableName)).Delete([]byte(key))
- return nil
- })
- return err
- }
- /*
- //List table example usage
- //Assume the value is stored as a struct named "groupstruct"
- entries, err := sysdb.ListTable("test")
- if err != nil {
- panic(err)
- }
- for _, keypairs := range entries{
- log.Println(string(keypairs[0]))
- group := new(groupstruct)
- json.Unmarshal(keypairs[1], &group)
- log.Println(group);
- }
- */
- func (d *Database) ListTable(tableName string) ([][][]byte, error) {
- var results [][][]byte
- err := d.Db.View(func(tx *bolt.Tx) error {
- b := tx.Bucket([]byte(tableName))
- c := b.Cursor()
- for k, v := c.First(); k != nil; k, v = c.Next() {
- results = append(results, [][]byte{k, v})
- }
- return nil
- })
- return results, err
- }
- func (d *Database) Close() {
- d.Db.Close()
- return
- }
|