updating readme and package comments

This commit is contained in:
Steve Domino 2015-07-07 17:37:08 -06:00
parent f06bf129bb
commit 09d4cba6cf
2 changed files with 98 additions and 29 deletions

View File

@ -1,2 +1,52 @@
scribble scribble
==== --------
`golang-scribble` (Golang package: `scribble`) is a tiny JSON flat file store
### Installation
Install using `go get github.com/pagodabox/golang-scribble`.
### Usage
Create a 'transaction' for scribble to transact.
`t := scribble.Transaction{Action: "read", Collection: "records", ResourceID: "<UniqueID>", Container: &v}`
+ Action - the action for scribble to perform
+ write - write to the scribble db
+ read - read from the scribble db
+ readall - read from the scribble db (all files in a collection)
+ delete - remove a record from the scribble db
+ Collection - the folder scribble will create to store grouped records
+ ResourceID - the unique ID of the resource being stored (bson, uuid, etc.)
+ Container - the Struct that contains the data scribble will marshal into the store, or what it will unmarshal into from the store
#### Full Example
```go
// a new scribble driver, providing the directory where it will be writing to, and a qualified logger to which it can send any output.
database, err := scribble.New(dir, logger)
if err != nil {
fmt.Println("Error", err)
}
// this is what scribble will either marshal from when writing, or unmarshal into when reading
record := Record{}
// create a new transaction for scribble to run
t := scribble.Transaction{Action: "read", Collection: "records", ResourceID: "<UniqueID>", Container: &record}
// have scribble attempt to run the transaction
if err := database.Transact(t); err != nil {
fmt.Println("Error", err)
}
```
For an example of a qualified logger see [here](http://godoc.org/github.com/pagodabox/golang-hatchet).
### Documentation
Complete documentation is available on [godoc](http://godoc.org/github.com/pagodabox/golang-scribble).

View File

@ -5,6 +5,10 @@
// at http://mozilla.org/MPL/2.0/. // at http://mozilla.org/MPL/2.0/.
// //
// scribble is a tiny JSON flat file store. It uses transactions that tell it what
// actions to perform, where it is to store data, and what it is going to write
// that data from, or read the data into. It creates a very simple database
// structure under a specified directory
package scribble package scribble
import ( import (
@ -19,29 +23,29 @@ import (
"github.com/pagodabox/golang-hatchet" "github.com/pagodabox/golang-hatchet"
) )
// const Version = "0.1.0"
const Version = "0.0.1"
//
type ( type (
// Driver // a Driver is what is used to interact with the scribble database. It runs
// transactions, and provides log output
Driver struct { Driver struct {
mutexes map[string]sync.Mutex mutexes map[string]sync.Mutex
dir string dir string // the directory where scribble will create the database
log hatchet.Logger log hatchet.Logger // the logger scirbble will log to
} }
// Transaction represents // a Transactions is what is used by a Driver to complete database operations
Transaction struct { Transaction struct {
Action string Action string // the action for scribble to preform
Collection string Collection string // the forlder for scribble to read/write to/from
ResourceID string ResourceID string // the unique ID of the record
Container interface{} Container interface{} // what scribble will marshal from or unmarshal into
} }
) )
// New // New creates a new scribble database at the desired directory location, and
// returns a *Driver to then use for interacting with the database
func New(dir string, logger hatchet.Logger) (*Driver, error) { func New(dir string, logger hatchet.Logger) (*Driver, error) {
fmt.Printf("Creating database directory at '%v'...\n", dir) fmt.Printf("Creating database directory at '%v'...\n", dir)
@ -57,7 +61,7 @@ func New(dir string, logger hatchet.Logger) (*Driver, error) {
log: logger, log: logger,
} }
// // create database
if err := mkDir(scribble.dir); err != nil { if err := mkDir(scribble.dir); err != nil {
return nil, err return nil, err
} }
@ -66,10 +70,11 @@ func New(dir string, logger hatchet.Logger) (*Driver, error) {
return scribble, nil return scribble, nil
} }
// Transact // Transact determins the type of transactions to be run, and calls the appropriate
// method to complete the operation
func (d *Driver) Transact(trans Transaction) error { func (d *Driver) Transact(trans Transaction) error {
// // determin transaction to be run
switch trans.Action { switch trans.Action {
case "write": case "write":
return d.write(trans) return d.write(trans)
@ -86,9 +91,10 @@ func (d *Driver) Transact(trans Transaction) error {
return nil return nil
} }
// private // write locks the database and then proceeds to write the data represented by a
// transaction.Container. It will create a direcotry that represents the collection
// write // to wich the record belongs (if it doesn't already exist), and write a file
// (named by he transaction.ResourceID) to that directory
func (d *Driver) write(trans Transaction) error { func (d *Driver) write(trans Transaction) error {
mutex := d.getOrCreateMutex(trans.Collection) mutex := d.getOrCreateMutex(trans.Collection)
@ -103,12 +109,12 @@ func (d *Driver) write(trans Transaction) error {
return err return err
} }
// // create collection directory
if err := mkDir(dir); err != nil { if err := mkDir(dir); err != nil {
return err return err
} }
// // write marshaled data to a file, named by the resourceID
if err := ioutil.WriteFile(dir+"/"+trans.ResourceID, b, 0666); err != nil { if err := ioutil.WriteFile(dir+"/"+trans.ResourceID, b, 0666); err != nil {
return err return err
} }
@ -118,16 +124,20 @@ func (d *Driver) write(trans Transaction) error {
return nil return nil
} }
// read // read does the opposite operation as write. Reading a record from the database
// (named by the transaction.resourceID, found in the transaction.Collection), and
// unmarshaling the data into the transaction.Container
func (d *Driver) read(trans Transaction) error { func (d *Driver) read(trans Transaction) error {
dir := d.dir + "/" + trans.Collection dir := d.dir + "/" + trans.Collection
// read record from database
b, err := ioutil.ReadFile(dir + "/" + trans.ResourceID) b, err := ioutil.ReadFile(dir + "/" + trans.ResourceID)
if err != nil { if err != nil {
return err return err
} }
// unmarshal data into the transaction.Container
if err := json.Unmarshal(b, trans.Container); err != nil { if err := json.Unmarshal(b, trans.Container); err != nil {
return err return err
} }
@ -135,30 +145,35 @@ func (d *Driver) read(trans Transaction) error {
return nil return nil
} }
// readAll // readAll does the same operation as read, reading all the records in the specified
// transaction.Collection
func (d *Driver) readAll(trans Transaction) error { func (d *Driver) readAll(trans Transaction) error {
dir := d.dir + "/" + trans.Collection dir := d.dir + "/" + trans.Collection
// // read all the files in the transaction.Collection
files, err := ioutil.ReadDir(dir) files, err := ioutil.ReadDir(dir)
// an error here just means an empty collection so do nothing
if err != nil { if err != nil {
// an error here just means an empty collection so do nothing
} }
// the files read from the database
var f []string var f []string
// iterate over each of the files, attempting to read the file. If successful
// append the files to the collection of read files
for _, file := range files { for _, file := range files {
b, err := ioutil.ReadFile(dir + "/" + file.Name()) b, err := ioutil.ReadFile(dir + "/" + file.Name())
if err != nil { if err != nil {
return err return err
} }
// append read file
f = append(f, string(b)) f = append(f, string(b))
} }
// // unmarhsal the read files as a comma delimeted byte array
if err := json.Unmarshal([]byte("["+strings.Join(f, ",")+"]"), trans.Container); err != nil { if err := json.Unmarshal([]byte("["+strings.Join(f, ",")+"]"), trans.Container); err != nil {
return err return err
} }
@ -166,7 +181,8 @@ func (d *Driver) readAll(trans Transaction) error {
return nil return nil
} }
// delete // delete locks that database and then proceeds to remove the record (specified by
// transaction.ResourceID) from the collection
func (d *Driver) delete(trans Transaction) error { func (d *Driver) delete(trans Transaction) error {
mutex := d.getOrCreateMutex(trans.Collection) mutex := d.getOrCreateMutex(trans.Collection)
@ -174,6 +190,7 @@ func (d *Driver) delete(trans Transaction) error {
dir := d.dir + "/" + trans.Collection dir := d.dir + "/" + trans.Collection
// remove record from database
err := os.Remove(dir + "/" + trans.ResourceID) err := os.Remove(dir + "/" + trans.ResourceID)
if err != nil { if err != nil {
return err return err
@ -186,7 +203,8 @@ func (d *Driver) delete(trans Transaction) error {
// helpers // helpers
// getOrCreateMutex // getOrCreateMutex creates a new collection specific mutex any time a collection
// is being modfied to avoid unsafe operations
func (d *Driver) getOrCreateMutex(collection string) sync.Mutex { func (d *Driver) getOrCreateMutex(collection string) sync.Mutex {
c, ok := d.mutexes[collection] c, ok := d.mutexes[collection]
@ -200,7 +218,8 @@ func (d *Driver) getOrCreateMutex(collection string) sync.Mutex {
return c return c
} }
// mkDir // mkDir is a simple wrapper that attempts to make a directory at a specified
// location
func mkDir(d string) error { func mkDir(d string) error {
// //