Implemented storage interface
This commit is contained in:
parent
8b3914eba5
commit
e0a5fa281b
@ -4,7 +4,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,8 +20,9 @@ type Collection[T any] interface {
|
|||||||
// collection is a hash map of homogeneous data.
|
// collection is a hash map of homogeneous data.
|
||||||
type collection[T any] struct {
|
type collection[T any] struct {
|
||||||
data sync.Map
|
data sync.Map
|
||||||
|
storage Storage[T]
|
||||||
name string
|
name string
|
||||||
directory string
|
root string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new collection with the given name.
|
// New creates a new collection with the given name.
|
||||||
@ -35,7 +35,6 @@ func New[T any](directories ...string) (*collection[T], error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
directories = append([]string{home, ".ocean"}, directories...)
|
directories = append([]string{home, ".ocean"}, directories...)
|
||||||
directories = append(directories, name)
|
|
||||||
directory := filepath.Join(directories...)
|
directory := filepath.Join(directories...)
|
||||||
err = os.MkdirAll(directory, 0700)
|
err = os.MkdirAll(directory, 0700)
|
||||||
|
|
||||||
@ -44,11 +43,12 @@ func New[T any](directories ...string) (*collection[T], error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := &collection[T]{
|
c := &collection[T]{
|
||||||
name: directories[len(directories)-1],
|
name: name,
|
||||||
directory: directory,
|
root: directory,
|
||||||
|
storage: &DirectoryStorage[T]{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, c.loadFromDisk()
|
return c, c.storage.Init(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All returns a channel of all objects in the collection.
|
// All returns a channel of all objects in the collection.
|
||||||
@ -100,7 +100,7 @@ func (c *collection[T]) Get(key string) (*T, error) {
|
|||||||
// Set sets the value for the given key.
|
// Set sets the value for the given key.
|
||||||
func (c *collection[T]) Set(key string, value *T) {
|
func (c *collection[T]) Set(key string, value *T) {
|
||||||
c.data.Store(key, value)
|
c.data.Store(key, value)
|
||||||
err := c.writeFileToDisk(key, value)
|
err := c.storage.Set(key, value)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -114,7 +114,7 @@ func (c *collection[T]) Delete(key string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.data.Delete(key)
|
c.data.Delete(key)
|
||||||
os.Remove(c.keyFile(key))
|
c.storage.Delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists returns whether or not the key exists.
|
// Exists returns whether or not the key exists.
|
||||||
@ -130,72 +130,3 @@ func (c *collection[T]) Clear() {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// keyFile returns the file path for the given key.
|
|
||||||
func (c *collection[T]) keyFile(key string) string {
|
|
||||||
return filepath.Join(c.directory, key+".json")
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadFromDisk loads the collection data from the disk.
|
|
||||||
func (c *collection[T]) loadFromDisk() error {
|
|
||||||
dir, err := os.Open(c.directory)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer dir.Close()
|
|
||||||
files, err := dir.Readdirnames(0)
|
|
||||||
|
|
||||||
for _, key := range files {
|
|
||||||
fileError := c.loadFileFromDisk(key)
|
|
||||||
|
|
||||||
if fileError != nil {
|
|
||||||
return fileError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadFileFromDisk loads a single file from the disk.
|
|
||||||
func (c *collection[T]) loadFileFromDisk(fileName string) error {
|
|
||||||
file, err := os.Open(filepath.Join(c.directory, fileName))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
value := new(T)
|
|
||||||
decoder := NewDecoder(file)
|
|
||||||
err = decoder.Decode(value)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
file.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
key := strings.TrimSuffix(fileName, ".json")
|
|
||||||
c.data.Store(key, value)
|
|
||||||
return file.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeFileToDisk writes the value for the key to disk as a JSON file.
|
|
||||||
func (c *collection[T]) writeFileToDisk(key string, value *T) error {
|
|
||||||
fileName := c.keyFile(key)
|
|
||||||
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder := NewEncoder(file)
|
|
||||||
err = encoder.Encode(value)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
file.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return file.Close()
|
|
||||||
}
|
|
||||||
|
100
DirectoryStorage.go
Normal file
100
DirectoryStorage.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package ocean
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DirectoryStorage creates a directory and stores every record in a separate file.
|
||||||
|
type DirectoryStorage[T any] struct {
|
||||||
|
collection *collection[T]
|
||||||
|
directory string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init loads all existing records from the directory.
|
||||||
|
func (ds *DirectoryStorage[T]) Init(c *collection[T]) error {
|
||||||
|
ds.collection = c
|
||||||
|
ds.directory = filepath.Join(c.root, c.name)
|
||||||
|
os.Mkdir(ds.directory, 0700)
|
||||||
|
return ds.loadFromDisk()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set saves the value in a file.
|
||||||
|
func (ds *DirectoryStorage[T]) Set(key string, value *T) error {
|
||||||
|
return ds.writeFileToDisk(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes the file for the given key.
|
||||||
|
func (ds *DirectoryStorage[T]) Delete(key string) error {
|
||||||
|
return os.Remove(ds.keyFile(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyFile returns the file path for the given key.
|
||||||
|
func (ds *DirectoryStorage[T]) keyFile(key string) string {
|
||||||
|
return filepath.Join(ds.directory, key+".json")
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadFromDisk loads the collection data from the disk.
|
||||||
|
func (ds *DirectoryStorage[T]) loadFromDisk() error {
|
||||||
|
dir, err := os.Open(ds.directory)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer dir.Close()
|
||||||
|
files, err := dir.Readdirnames(0)
|
||||||
|
|
||||||
|
for _, fileName := range files {
|
||||||
|
fileError := ds.loadFileFromDisk(fileName)
|
||||||
|
|
||||||
|
if fileError != nil {
|
||||||
|
return fileError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadFileFromDisk loads a single file from the disk.
|
||||||
|
func (ds *DirectoryStorage[T]) loadFileFromDisk(fileName string) error {
|
||||||
|
file, err := os.Open(filepath.Join(ds.directory, fileName))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := new(T)
|
||||||
|
decoder := NewDecoder(file)
|
||||||
|
err = decoder.Decode(value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
key := strings.TrimSuffix(fileName, ".json")
|
||||||
|
ds.collection.data.Store(key, value)
|
||||||
|
return file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeFileToDisk writes the value for the key to disk as a JSON file.
|
||||||
|
func (ds *DirectoryStorage[T]) writeFileToDisk(key string, value *T) error {
|
||||||
|
fileName := ds.keyFile(key)
|
||||||
|
file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder := NewEncoder(file)
|
||||||
|
err = encoder.Encode(value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
file.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return file.Close()
|
||||||
|
}
|
69
FileStorage.go
Normal file
69
FileStorage.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package ocean
|
||||||
|
|
||||||
|
// import (
|
||||||
|
// "bufio"
|
||||||
|
// "encoding/json"
|
||||||
|
// "io"
|
||||||
|
// "os"
|
||||||
|
// "path/filepath"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// type FileStorage[T any] struct {
|
||||||
|
// collection *collection[T]
|
||||||
|
// dirty chan struct{}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (fs *FileStorage[T]) Init(c *collection[T]) error {
|
||||||
|
// fs.collection = c
|
||||||
|
// fileName := filepath.Join(c.root, c.name+".dat")
|
||||||
|
// stream, err := os.OpenFile(fileName, os.O_RDONLY, 0600)
|
||||||
|
//
|
||||||
|
// if os.IsNotExist(err) {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// defer stream.Close()
|
||||||
|
// return fs.readRecords(stream)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (fs *FileStorage[T]) Set(key string, value *T) error {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (fs *FileStorage[T]) Delete(key string) error {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // readRecords reads the entire collection.
|
||||||
|
// func (fs *FileStorage[T]) readRecords(stream io.Reader) error {
|
||||||
|
// var (
|
||||||
|
// key string
|
||||||
|
// value []byte
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// scanner := bufio.NewScanner(stream)
|
||||||
|
//
|
||||||
|
// for scanner.Scan() {
|
||||||
|
// if key == "" {
|
||||||
|
// key = scanner.Text()
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// value = scanner.Bytes()
|
||||||
|
// object := new(T)
|
||||||
|
// err := json.Unmarshal(value, object)
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fs.collection.data.Store(key, object)
|
||||||
|
// key = ""
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return nil
|
||||||
|
// }
|
7
Storage.go
Normal file
7
Storage.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package ocean
|
||||||
|
|
||||||
|
type Storage[T any] interface {
|
||||||
|
Init(c *collection[T]) error
|
||||||
|
Set(key string, value *T) error
|
||||||
|
Delete(key string) error
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user