revert: 移除 storage 包,不合理的设计
This commit is contained in:
parent
a43fb4faea
commit
3e956b64cf
|
@ -1,59 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
// NewGlobalData 创建全局数据
|
|
||||||
func NewGlobalData[T any](name string, storage GlobalDataStorage[T]) (*GlobalData[T], error) {
|
|
||||||
data := &GlobalData[T]{
|
|
||||||
storage: storage,
|
|
||||||
name: name,
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
data.data, err = storage.Load(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalData 全局数据
|
|
||||||
type GlobalData[T any] struct {
|
|
||||||
storage GlobalDataStorage[T] // 全局数据存储器
|
|
||||||
name string // 全局数据名称
|
|
||||||
data T // 数据
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName 获取名称
|
|
||||||
func (slf *GlobalData[T]) GetName() string {
|
|
||||||
return slf.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetData 获取数据
|
|
||||||
func (slf *GlobalData[T]) GetData() T {
|
|
||||||
return slf.data
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadData 加载数据
|
|
||||||
func (slf *GlobalData[T]) LoadData() error {
|
|
||||||
data, err := slf.storage.Load(slf.GetName())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slf.data = data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveData 保存数据
|
|
||||||
func (slf *GlobalData[T]) SaveData() error {
|
|
||||||
return slf.storage.Save(slf.GetName(), slf.GetData())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle 处理数据
|
|
||||||
func (slf *GlobalData[T]) Handle(handler func(name string, data T)) *GlobalData[T] {
|
|
||||||
handler(slf.GetName(), slf.GetData())
|
|
||||||
return slf
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleWithCallback 处理数据
|
|
||||||
func (slf *GlobalData[T]) HandleWithCallback(handler func(name string, data T) error, callback func(err error)) *GlobalData[T] {
|
|
||||||
callback(handler(slf.GetName(), slf.GetData()))
|
|
||||||
return slf
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
// GlobalDataStorage 全局数据存储器接口
|
|
||||||
type GlobalDataStorage[T any] interface {
|
|
||||||
// Load 加载全局数据
|
|
||||||
// - 当全局数据不存在时,应当返回新的全局数据实例
|
|
||||||
Load(name string) (T, error)
|
|
||||||
// Save 保存全局数据
|
|
||||||
Save(name string, data T) error
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/generic"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewIndexData 创建索引数据
|
|
||||||
func NewIndexData[I generic.Ordered, T IndexDataItem[I]](name string, storage IndexDataStorage[I, T]) (*IndexData[I, T], error) {
|
|
||||||
data := &IndexData[I, T]{
|
|
||||||
storage: storage,
|
|
||||||
name: name,
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
data.data, err = storage.LoadAll(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IndexData 全局数据
|
|
||||||
type IndexData[I generic.Ordered, T IndexDataItem[I]] struct {
|
|
||||||
storage IndexDataStorage[I, T] // 存储器
|
|
||||||
name string // 数据组名称
|
|
||||||
data map[I]T // 数据
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName 获取名称
|
|
||||||
func (slf *IndexData[I, T]) GetName() string {
|
|
||||||
return slf.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetData 获取数据
|
|
||||||
func (slf *IndexData[I, T]) GetData(index I) T {
|
|
||||||
data, _ := slf.data[index]
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllData 获取所有数据
|
|
||||||
func (slf *IndexData[I, T]) GetAllData() map[I]T {
|
|
||||||
return slf.data
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadData 加载数据
|
|
||||||
func (slf *IndexData[I, T]) LoadData(index I) error {
|
|
||||||
data, err := slf.storage.Load(slf.GetName(), index)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slf.data[index] = data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadAllData 加载所有数据
|
|
||||||
func (slf *IndexData[I, T]) LoadAllData() error {
|
|
||||||
data, err := slf.storage.LoadAll(slf.GetName())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slf.data = data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveData 保存数据
|
|
||||||
func (slf *IndexData[I, T]) SaveData(index I) error {
|
|
||||||
return slf.storage.Save(slf.GetName(), index, slf.GetData(index))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveAllData 保存所有数据
|
|
||||||
// - errHandle 错误处理中如果返回 false 将重试,否则跳过当前保存下一个
|
|
||||||
func (slf *IndexData[I, T]) SaveAllData() error {
|
|
||||||
return slf.storage.SaveAll(slf.GetName(), slf.GetAllData())
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteData 删除数据
|
|
||||||
func (slf *IndexData[I, T]) DeleteData(index I) *IndexData[I, T] {
|
|
||||||
slf.storage.Delete(slf.GetName(), index)
|
|
||||||
delete(slf.data, index)
|
|
||||||
return slf
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteAllData 删除所有数据
|
|
||||||
func (slf *IndexData[I, T]) DeleteAllData() *IndexData[I, T] {
|
|
||||||
slf.storage.DeleteAll(slf.GetName())
|
|
||||||
for k := range slf.data {
|
|
||||||
delete(slf.data, k)
|
|
||||||
}
|
|
||||||
return slf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle 处理数据
|
|
||||||
func (slf *IndexData[I, T]) Handle(index I, handler func(name string, index I, data T)) *IndexData[I, T] {
|
|
||||||
handler(slf.GetName(), index, slf.GetData(index))
|
|
||||||
return slf
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleWithCallback 处理数据
|
|
||||||
func (slf *IndexData[I, T]) HandleWithCallback(index I, handler func(name string, index I, data T) error, callback func(err error)) *IndexData[I, T] {
|
|
||||||
callback(handler(slf.GetName(), index, slf.GetData(index)))
|
|
||||||
return slf
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
import "github.com/kercylan98/minotaur/utils/generic"
|
|
||||||
|
|
||||||
type IndexDataItem[I generic.Ordered] interface {
|
|
||||||
GetIndex() I
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/generic"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IndexDataStorage 全局数据存储器接口
|
|
||||||
type IndexDataStorage[I generic.Ordered, T IndexDataItem[I]] interface {
|
|
||||||
// Load 加载特定索引数据
|
|
||||||
// - 通常情况下当数据不存在时,应当返回空指针
|
|
||||||
Load(name string, index I) (T, error)
|
|
||||||
// LoadAll 加载所有数据
|
|
||||||
LoadAll(name string) (map[I]T, error)
|
|
||||||
// Save 保存特定索引数据
|
|
||||||
Save(name string, index I, data T) error
|
|
||||||
// SaveAll 保存所有数据
|
|
||||||
SaveAll(name string, data map[I]T) error
|
|
||||||
// Delete 删除特定索引数据
|
|
||||||
Delete(name string, index I) error
|
|
||||||
// DeleteAll 删除所有数据
|
|
||||||
DeleteAll(name string) error
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package storages
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
// FileStorageEncoder 全局数据文件存储编码器
|
|
||||||
type FileStorageEncoder[T any] func(data T) ([]byte, error)
|
|
||||||
|
|
||||||
// FileStorageDecoder 全局数据文件存储解码器
|
|
||||||
type FileStorageDecoder[T any] func(bytes []byte, data T) error
|
|
||||||
|
|
||||||
// FileStorageJSONEncoder JSON 编码器
|
|
||||||
func FileStorageJSONEncoder[T any]() FileStorageEncoder[T] {
|
|
||||||
return func(data T) ([]byte, error) {
|
|
||||||
return json.Marshal(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileStorageJSONDecoder JSON 解码器
|
|
||||||
func FileStorageJSONDecoder[T any]() FileStorageDecoder[T] {
|
|
||||||
return func(bytes []byte, data T) error {
|
|
||||||
return json.Unmarshal(bytes, data)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
{"CreateAt":"2023-07-19T14:49:35.7235348+08:00","TotalCount":10}
|
|
|
@ -1 +0,0 @@
|
||||||
{"ID":"INDEX_001","Value":10}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package storages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/kercylan98/minotaur/utils/file"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// GlobalDataFileDefaultSuffix 是 GlobalDataFileStorage 的文件默认后缀
|
|
||||||
GlobalDataFileDefaultSuffix = "stock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewGlobalDataFileStorage 创建一个 GlobalDataFileStorage,dir 是文件存储目录,generate 是生成数据的函数,options 是可选参数
|
|
||||||
// - 生成的文件名为 ${name}.${suffix},可以通过 WithGlobalDataFileStorageSuffix 修改后缀
|
|
||||||
// - 默认使用 JSON 格式存储,可以通过 WithGlobalDataFileStorageEncoder 和 WithGlobalDataFileStorageDecoder 修改编码和解码函数
|
|
||||||
// - 内置了 JSON 编码和解码函数,可以通过 FileStorageJSONEncoder 和 FileStorageJSONDecoder 获取
|
|
||||||
func NewGlobalDataFileStorage[T any](dir string, generate func(name string) T, options ...GlobalDataFileStorageOption[T]) *GlobalDataFileStorage[T] {
|
|
||||||
abs, err := filepath.Abs(dir)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
storage := &GlobalDataFileStorage[T]{
|
|
||||||
dir: abs,
|
|
||||||
suffix: GlobalDataFileDefaultSuffix,
|
|
||||||
generate: generate,
|
|
||||||
encoder: FileStorageJSONEncoder[T](),
|
|
||||||
decoder: FileStorageJSONDecoder[T](),
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(storage)
|
|
||||||
}
|
|
||||||
return storage
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalDataFileStorage 用于存储全局数据的文件存储器
|
|
||||||
type GlobalDataFileStorage[T any] struct {
|
|
||||||
dir string
|
|
||||||
suffix string
|
|
||||||
generate func(name string) T
|
|
||||||
encoder FileStorageEncoder[T]
|
|
||||||
decoder FileStorageDecoder[T]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load 从文件中加载数据,如果文件不存在则使用 generate 生成数据
|
|
||||||
func (slf *GlobalDataFileStorage[T]) Load(name string) (T, error) {
|
|
||||||
bytes, err := file.ReadOnce(filepath.Join(slf.dir, fmt.Sprintf("%s.%s", name, slf.suffix)))
|
|
||||||
if err != nil {
|
|
||||||
return slf.generate(name), nil
|
|
||||||
}
|
|
||||||
var data = slf.generate(name)
|
|
||||||
return data, slf.decoder(bytes, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save 将数据保存到文件中
|
|
||||||
func (slf *GlobalDataFileStorage[T]) Save(name string, data T) error {
|
|
||||||
bytes, err := slf.encoder(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return file.WriterFile(filepath.Join(slf.dir, fmt.Sprintf("%s.%s", name, slf.suffix)), bytes)
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package storages_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage/storages"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleNewGlobalDataFileStorage() {
|
|
||||||
storage := storages.NewGlobalDataFileStorage[*GlobalData](".", func(name string) *GlobalData {
|
|
||||||
return &GlobalData{
|
|
||||||
CreateAt: time.Now(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println(storage != nil)
|
|
||||||
// Output:
|
|
||||||
// true
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package storages
|
|
||||||
|
|
||||||
// GlobalDataFileStorageOption 全局数据文件存储选项
|
|
||||||
type GlobalDataFileStorageOption[T any] func(storage *GlobalDataFileStorage[T])
|
|
||||||
|
|
||||||
// WithGlobalDataFileStorageEncoder 设置编码器
|
|
||||||
// - 默认为 FileStorageJSONEncoder 编码器
|
|
||||||
func WithGlobalDataFileStorageEncoder[T any](encoder FileStorageEncoder[T]) GlobalDataFileStorageOption[T] {
|
|
||||||
return func(storage *GlobalDataFileStorage[T]) {
|
|
||||||
storage.encoder = encoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithGlobalDataFileStorageDecoder 设置解码器
|
|
||||||
// - 默认为 FileStorageJSONDecoder 解码器
|
|
||||||
func WithGlobalDataFileStorageDecoder[T any](decoder FileStorageDecoder[T]) GlobalDataFileStorageOption[T] {
|
|
||||||
return func(storage *GlobalDataFileStorage[T]) {
|
|
||||||
storage.decoder = decoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithGlobalDataFileStorageSuffix 设置文件后缀
|
|
||||||
// - 默认为 GlobalDataFileDefaultSuffix
|
|
||||||
func WithGlobalDataFileStorageSuffix[T any](suffix string) GlobalDataFileStorageOption[T] {
|
|
||||||
return func(storage *GlobalDataFileStorage[T]) {
|
|
||||||
storage.suffix = suffix
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package storages_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage"
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage/storages"
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GlobalData struct {
|
|
||||||
CreateAt time.Time
|
|
||||||
TotalCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGlobalDataFileStorage_Save(t *testing.T) {
|
|
||||||
Convey("TestGlobalDataFileStorage_Save", t, func() {
|
|
||||||
data, err := storage.NewGlobalData[*GlobalData]("global_data_file_test", storages.NewGlobalDataFileStorage[*GlobalData]("./example-data", func(name string) *GlobalData {
|
|
||||||
return &GlobalData{
|
|
||||||
CreateAt: time.Now(),
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
data.Handle(func(name string, data *GlobalData) {
|
|
||||||
data.TotalCount = 10
|
|
||||||
})
|
|
||||||
So(data.SaveData(), ShouldBeNil)
|
|
||||||
So(data.GetData().TotalCount, ShouldEqual, 10)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGlobalDataFileStorage_Load(t *testing.T) {
|
|
||||||
Convey("TestGlobalDataFileStorage_Load", t, func() {
|
|
||||||
data, err := storage.NewGlobalData[*GlobalData]("global_data_file_test", storages.NewGlobalDataFileStorage[*GlobalData]("./example-data", func(name string) *GlobalData {
|
|
||||||
return &GlobalData{
|
|
||||||
CreateAt: time.Now(),
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(data.GetData().TotalCount, ShouldEqual, 10)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
package storages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/kercylan98/minotaur/utils/file"
|
|
||||||
"github.com/kercylan98/minotaur/utils/generic"
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// IndexDataFileDefaultSuffix 是 IndexDataFileStorage 的文件默认后缀
|
|
||||||
IndexDataFileDefaultSuffix = "stock"
|
|
||||||
|
|
||||||
indexNameFormat = "%s.%v.%s"
|
|
||||||
indexNameFormatTemp = "%s.%v.%s.temp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewIndexDataFileStorage 创建索引数据文件存储器
|
|
||||||
func NewIndexDataFileStorage[I generic.Ordered, T storage.IndexDataItem[I]](dir string, generate func(name string, index I) T, generateZero func(name string) T, options ...IndexDataFileStorageOption[I, T]) *IndexDataFileStorage[I, T] {
|
|
||||||
s := &IndexDataFileStorage[I, T]{
|
|
||||||
dir: dir,
|
|
||||||
suffix: IndexDataFileDefaultSuffix,
|
|
||||||
generate: generate,
|
|
||||||
generateZero: generateZero,
|
|
||||||
encoder: FileStorageJSONEncoder[T](),
|
|
||||||
decoder: FileStorageJSONDecoder[T](),
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(s)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// IndexDataFileStorage 索引数据文件存储器
|
|
||||||
type IndexDataFileStorage[I generic.Ordered, T storage.IndexDataItem[I]] struct {
|
|
||||||
dir string
|
|
||||||
suffix string
|
|
||||||
generate func(name string, index I) T
|
|
||||||
generateZero func(name string) T
|
|
||||||
encoder FileStorageEncoder[T]
|
|
||||||
decoder FileStorageDecoder[T]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *IndexDataFileStorage[I, T]) Load(name string, index I) (T, error) {
|
|
||||||
bytes, err := file.ReadOnce(filepath.Join(slf.dir, fmt.Sprintf(indexNameFormat, name, index, slf.suffix)))
|
|
||||||
if err != nil {
|
|
||||||
return slf.generate(name, index), nil
|
|
||||||
}
|
|
||||||
var data = slf.generate(name, index)
|
|
||||||
return data, slf.decoder(bytes, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *IndexDataFileStorage[I, T]) LoadAll(name string) (map[I]T, error) {
|
|
||||||
var result = make(map[I]T)
|
|
||||||
files, err := os.ReadDir(slf.dir)
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
for _, entry := range files {
|
|
||||||
if entry.IsDir() || !strings.HasPrefix(entry.Name(), name) || !strings.HasSuffix(entry.Name(), slf.suffix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
bytes, err := file.ReadOnce(filepath.Join(slf.dir, entry.Name()))
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
data := slf.generateZero(name)
|
|
||||||
if err := slf.decoder(bytes, data); err == nil {
|
|
||||||
result[data.GetIndex()] = data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *IndexDataFileStorage[I, T]) Save(name string, index I, data T) error {
|
|
||||||
bytes, err := slf.encoder(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return file.WriterFile(filepath.Join(slf.dir, fmt.Sprintf(indexNameFormat, name, index, slf.suffix)), bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *IndexDataFileStorage[I, T]) SaveAll(name string, data map[I]T) error {
|
|
||||||
var temps = make([]string, 0, len(data))
|
|
||||||
defer func() {
|
|
||||||
for _, temp := range temps {
|
|
||||||
_ = os.Remove(temp)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
for index, data := range data {
|
|
||||||
bytes, err := slf.encoder(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
path := filepath.Join(slf.dir, fmt.Sprintf(indexNameFormatTemp, name, index, slf.suffix))
|
|
||||||
temps = append(temps, path)
|
|
||||||
if err = file.WriterFile(path, bytes); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, temp := range temps {
|
|
||||||
if err := os.Rename(temp, strings.TrimSuffix(temp, ".temp")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *IndexDataFileStorage[I, T]) Delete(name string, index I) error {
|
|
||||||
return os.Remove(filepath.Join(slf.dir, fmt.Sprintf(indexNameFormat, name, index, slf.suffix)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *IndexDataFileStorage[I, T]) DeleteAll(name string) error {
|
|
||||||
files, err := os.ReadDir(slf.dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, entry := range files {
|
|
||||||
if entry.IsDir() || !strings.HasPrefix(entry.Name(), name) || !strings.HasSuffix(entry.Name(), slf.suffix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := os.Remove(filepath.Join(slf.dir, entry.Name())); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package storages_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage/storages"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleNewIndexDataFileStorage() {
|
|
||||||
storage := storages.NewIndexDataFileStorage[string, *IndexData[string]]("./example-data", func(name string, index string) *IndexData[string] {
|
|
||||||
return &IndexData[string]{ID: index}
|
|
||||||
}, func(name string) *IndexData[string] {
|
|
||||||
return new(IndexData[string])
|
|
||||||
})
|
|
||||||
|
|
||||||
fmt.Println(storage != nil)
|
|
||||||
// Output:
|
|
||||||
// true
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package storages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/generic"
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IndexDataFileStorageOption 索引数据文件存储器选项
|
|
||||||
type IndexDataFileStorageOption[I generic.Ordered, T storage.IndexDataItem[I]] func(storage *IndexDataFileStorage[I, T])
|
|
||||||
|
|
||||||
// WithIndexDataFileStorageEncoder 设置编码器
|
|
||||||
// - 默认为 FileStorageJSONEncoder 编码器
|
|
||||||
func WithIndexDataFileStorageEncoder[I generic.Ordered, T storage.IndexDataItem[I]](encoder FileStorageEncoder[T]) IndexDataFileStorageOption[I, T] {
|
|
||||||
return func(storage *IndexDataFileStorage[I, T]) {
|
|
||||||
storage.encoder = encoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithIndexDataFileStorageDecoder 设置解码器
|
|
||||||
// - 默认为 FileStorageJSONDecoder 解码器
|
|
||||||
func WithIndexDataFileStorageDecoder[I generic.Ordered, T storage.IndexDataItem[I]](decoder FileStorageDecoder[T]) IndexDataFileStorageOption[I, T] {
|
|
||||||
return func(storage *IndexDataFileStorage[I, T]) {
|
|
||||||
storage.decoder = decoder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithIndexDataFileStorageSuffix 设置文件后缀
|
|
||||||
// - 默认为 IndexDataFileDefaultSuffix
|
|
||||||
func WithIndexDataFileStorageSuffix[I generic.Ordered, T storage.IndexDataItem[I]](suffix string) IndexDataFileStorageOption[I, T] {
|
|
||||||
return func(storage *IndexDataFileStorage[I, T]) {
|
|
||||||
storage.suffix = suffix
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package storages_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage"
|
|
||||||
"github.com/kercylan98/minotaur/utils/storage/storages"
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IndexData[I string] struct {
|
|
||||||
ID I
|
|
||||||
Value int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (slf *IndexData[I]) GetIndex() I {
|
|
||||||
return slf.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIndexDataFileStorage_Save(t *testing.T) {
|
|
||||||
Convey("TestIndexDataFileStorage_Save", t, func() {
|
|
||||||
data, err := storage.NewIndexData[string, *IndexData[string]]("index_data_file_test", storages.NewIndexDataFileStorage[string, *IndexData[string]]("./example-data", func(name string, index string) *IndexData[string] {
|
|
||||||
return &IndexData[string]{ID: index}
|
|
||||||
}, func(name string) *IndexData[string] {
|
|
||||||
return new(IndexData[string])
|
|
||||||
}))
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
data.Handle("INDEX_001", func(name string, index string, data *IndexData[string]) {
|
|
||||||
data.Value = 10
|
|
||||||
})
|
|
||||||
if err := data.SaveData("INDEX_001"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
So(data.GetData("INDEX_001").Value, ShouldEqual, 10)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIndexDataFileStorage_Load(t *testing.T) {
|
|
||||||
Convey("TestIndexDataFileStorage_Load", t, func() {
|
|
||||||
data, err := storage.NewIndexData[string, *IndexData[string]]("index_data_file_test", storages.NewIndexDataFileStorage[string, *IndexData[string]]("./example-data", func(name string, index string) *IndexData[string] {
|
|
||||||
return &IndexData[string]{ID: index}
|
|
||||||
}, func(name string) *IndexData[string] {
|
|
||||||
return new(IndexData[string])
|
|
||||||
}))
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(data.GetData("INDEX_001").Value, ShouldEqual, 10)
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in New Issue