Add method to automatically create integer IDs

This commit is contained in:
boosh 2017-07-24 20:30:48 +01:00
parent da3a159a46
commit eabb4d6277
3 changed files with 98 additions and 3 deletions

View File

@ -51,6 +51,18 @@ if err := db.Delete("fish", ""); err != nil {
} }
``` ```
Also supports automatically generating integer IDs.
```
// Write a fish to the database
fish := Fish{}
id, err := db.WriteAutoId("fish", fish); if err != nil {
fmt.Println("Error", err)
}
// ID == 1
```
## Documentation ## Documentation
- Complete documentation is available on [godoc](http://godoc.org/github.com/nanobox-io/golang-scribble). - Complete documentation is available on [godoc](http://godoc.org/github.com/nanobox-io/golang-scribble).
- Coverage Report is available on [gocover](https://gocover.io/github.com/nanobox-io/golang-scribble) - Coverage Report is available on [gocover](https://gocover.io/github.com/nanobox-io/golang-scribble)

View File

@ -10,13 +10,15 @@ import (
"sync" "sync"
"github.com/jcelliott/lumber" "github.com/jcelliott/lumber"
"path"
"strings"
"strconv"
) )
// Version is the current version of the project // Version is the current version of the project
const Version = "1.0.4" const Version = "1.0.4"
type ( type (
// Logger is a generic logger interface // Logger is a generic logger interface
Logger interface { Logger interface {
Fatal(string, ...interface{}) Fatal(string, ...interface{})
@ -98,6 +100,11 @@ func (d *Driver) Write(collection, resource string, v interface{}) error {
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
return d.writeFile(collection, resource, v)
}
// Writes a file to disk
func (d *Driver) writeFile(collection string, resource string, v interface{}) error {
// //
dir := filepath.Join(d.dir, collection) dir := filepath.Join(d.dir, collection)
fnlPath := filepath.Join(dir, resource+".json") fnlPath := filepath.Join(dir, resource+".json")
@ -123,6 +130,51 @@ func (d *Driver) Write(collection, resource string, v interface{}) error {
return os.Rename(tmpPath, fnlPath) return os.Rename(tmpPath, fnlPath)
} }
// Locks the database, gets the next available integer resource ID and attempts to write the
// record to the database under the [collection] specified with the generated [resource] ID
func (d *Driver) WriteAutoId(collection string, v interface{}) (resourceId int64, err error) {
resourceId = -1
// ensure there is a place to save record
if collection == "" {
return resourceId, fmt.Errorf("Missing collection - no place to save record!")
}
mutex := d.getOrCreateMutex(collection)
mutex.Lock()
defer mutex.Unlock()
// list the directory, sort it, take the last entry then parse and increment the last ID
files, err := ioutil.ReadDir(d.dir)
if err != nil {
fmt.Printf("Error listing directory %s: %s", d.dir, err.Error())
return resourceId, err
}
if len(files) == 0 {
resourceId = 1
} else {
lastFile := files[len(files)-1]
ext := path.Ext(lastFile.Name())
baseName := strings.TrimSuffix(lastFile.Name(), ext)
resourceId, err := strconv.ParseInt(baseName, 10, 8)
if err != nil {
fmt.Printf("Error parsing string '%s' as integer", baseName, err.Error())
return resourceId, err
}
}
stringResourceId := fmt.Sprintf("%d", resourceId)
fmt.Printf("Writing resource under auto-generated ID '%s'\n", stringResourceId)
err = d.writeFile(collection, stringResourceId, v)
return resourceId, err
}
// Read a record from the database // Read a record from the database
func (d *Driver) Read(collection, resource string, v interface{}) error { func (d *Driver) Read(collection, resource string, v interface{}) error {

View File

@ -3,6 +3,7 @@ package scribble
import ( import (
"os" "os"
"testing" "testing"
"fmt"
) )
// //
@ -85,6 +86,36 @@ func TestWriteAndRead(t *testing.T) {
destroySchool() destroySchool()
} }
//
func TestWriteAutoIdAndRead(t *testing.T) {
createDB()
// add fish to database
id, err := db.WriteAutoId(collection, redfish);
if err != nil {
t.Error("Create fish failed: ", err.Error())
}
if id <= 0 {
t.Error("Auto-generated ID should have been > 0")
}
stringId := fmt.Sprintf("%d", id)
// read fish from database
if err := db.Read(collection, stringId, &onefish); err != nil {
t.Error("Failed to read: ", err.Error())
}
//
if onefish.Type != "red" {
t.Error("Expected red fish, got: ", onefish.Type)
}
destroySchool()
}
// //
func TestReadall(t *testing.T) { func TestReadall(t *testing.T) {