updating readme and package comments
This commit is contained in:
parent
f06bf129bb
commit
09d4cba6cf
52
README.md
52
README.md
@ -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).
|
||||||
|
75
scribble.go
75
scribble.go
@ -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 {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user