diff --git a/utils/storage/global_data.go b/utils/storage/global_data.go deleted file mode 100644 index 54ebaaf..0000000 --- a/utils/storage/global_data.go +++ /dev/null @@ -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 -} diff --git a/utils/storage/global_data_storage.go b/utils/storage/global_data_storage.go deleted file mode 100644 index 8103ecd..0000000 --- a/utils/storage/global_data_storage.go +++ /dev/null @@ -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 -} diff --git a/utils/storage/index_data.go b/utils/storage/index_data.go deleted file mode 100644 index 2b01480..0000000 --- a/utils/storage/index_data.go +++ /dev/null @@ -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 -} diff --git a/utils/storage/index_data_item.go b/utils/storage/index_data_item.go deleted file mode 100644 index 86da5b6..0000000 --- a/utils/storage/index_data_item.go +++ /dev/null @@ -1,7 +0,0 @@ -package storage - -import "github.com/kercylan98/minotaur/utils/generic" - -type IndexDataItem[I generic.Ordered] interface { - GetIndex() I -} diff --git a/utils/storage/index_data_storage.go b/utils/storage/index_data_storage.go deleted file mode 100644 index 1f72925..0000000 --- a/utils/storage/index_data_storage.go +++ /dev/null @@ -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 -} diff --git a/utils/storage/storages/encode.go b/utils/storage/storages/encode.go deleted file mode 100644 index f34958d..0000000 --- a/utils/storage/storages/encode.go +++ /dev/null @@ -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) - } -} diff --git a/utils/storage/storages/example-data/global_data_file_test.stock b/utils/storage/storages/example-data/global_data_file_test.stock deleted file mode 100644 index 7359430..0000000 --- a/utils/storage/storages/example-data/global_data_file_test.stock +++ /dev/null @@ -1 +0,0 @@ -{"CreateAt":"2023-07-19T14:49:35.7235348+08:00","TotalCount":10} \ No newline at end of file diff --git a/utils/storage/storages/example-data/index_data_file_test.INDEX_001.stock b/utils/storage/storages/example-data/index_data_file_test.INDEX_001.stock deleted file mode 100644 index c730b47..0000000 --- a/utils/storage/storages/example-data/index_data_file_test.INDEX_001.stock +++ /dev/null @@ -1 +0,0 @@ -{"ID":"INDEX_001","Value":10} \ No newline at end of file diff --git a/utils/storage/storages/global_data_file.go b/utils/storage/storages/global_data_file.go deleted file mode 100644 index bfe63b4..0000000 --- a/utils/storage/storages/global_data_file.go +++ /dev/null @@ -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) -} diff --git a/utils/storage/storages/global_data_file_example_test.go b/utils/storage/storages/global_data_file_example_test.go deleted file mode 100644 index a9f3186..0000000 --- a/utils/storage/storages/global_data_file_example_test.go +++ /dev/null @@ -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 -} diff --git a/utils/storage/storages/global_data_file_options.go b/utils/storage/storages/global_data_file_options.go deleted file mode 100644 index 1f05719..0000000 --- a/utils/storage/storages/global_data_file_options.go +++ /dev/null @@ -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 - } -} diff --git a/utils/storage/storages/global_data_file_test.go b/utils/storage/storages/global_data_file_test.go deleted file mode 100644 index 6ff9996..0000000 --- a/utils/storage/storages/global_data_file_test.go +++ /dev/null @@ -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) - }) -} diff --git a/utils/storage/storages/index_data_file.go b/utils/storage/storages/index_data_file.go deleted file mode 100644 index f634a6c..0000000 --- a/utils/storage/storages/index_data_file.go +++ /dev/null @@ -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 -} diff --git a/utils/storage/storages/index_data_file_example_test.go b/utils/storage/storages/index_data_file_example_test.go deleted file mode 100644 index f6c865d..0000000 --- a/utils/storage/storages/index_data_file_example_test.go +++ /dev/null @@ -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 -} diff --git a/utils/storage/storages/index_data_file_options.go b/utils/storage/storages/index_data_file_options.go deleted file mode 100644 index 9d8bec1..0000000 --- a/utils/storage/storages/index_data_file_options.go +++ /dev/null @@ -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 - } -} diff --git a/utils/storage/storages/index_data_file_test.go b/utils/storage/storages/index_data_file_test.go deleted file mode 100644 index fc0b529..0000000 --- a/utils/storage/storages/index_data_file_test.go +++ /dev/null @@ -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) - }) -}