create project

This commit is contained in:
tursom 2023-04-18 14:24:20 +08:00
commit e9bcb96f3b
19 changed files with 940 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

15
go.mod Normal file
View File

@ -0,0 +1,15 @@
module kvs
go 1.20
require (
github.com/mattn/go-sqlite3 v1.14.16
github.com/syndtr/goleveldb v1.0.0
github.com/tursom/GoCollections v0.2.7
google.golang.org/protobuf v1.30.0
)
require (
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/timandy/routine v1.1.1 // indirect
)

45
go.sum Normal file
View File

@ -0,0 +1,45 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/timandy/routine v1.1.1 h1:6/Z7qLFZj3GrzuRksBFzIG8YGUh8CLhjnnMePBQTrEI=
github.com/timandy/routine v1.1.1/go.mod h1:OZHPOKSvqL/ZvqXFkNZyit0xIVelERptYXdAHH00adQ=
github.com/tursom/GoCollections v0.2.7 h1:WKbtQt1wuBoYhTXLCahr+BiFPJI8pUEQtsFuKk+V2Cc=
github.com/tursom/GoCollections v0.2.7/go.mod h1:uGlIIUhnuK01+AlzYtS/P+ZfqA2Q6MEulrPChiwf3KI=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

59
kv/ArrayCodec.go Normal file
View File

@ -0,0 +1,59 @@
package kv
import (
"bytes"
"io"
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
)
// 不推荐使用
type (
arrayCodec[V any] struct {
lang.BaseObject
codec Codec[io.Reader, V]
}
)
func ArrayCodec[V any](codec Codec[io.Reader, V]) Codec[[]byte, []V] {
return &arrayCodec[V]{codec: codec}
}
func (a *arrayCodec[V]) encode(v2 []V) []byte {
var bs []byte
for _, v := range v2 {
encode := a.codec.encode(v)
all, err := io.ReadAll(encode)
if err != nil {
panic(exceptions.Package(err))
}
bs = append(bs, all...)
}
return bs
}
func (a *arrayCodec[V]) decode(v1 []byte) []V {
if len(v1) == 0 {
return []V{}
}
reader := bytes.NewReader(v1)
var values []V
for func() bool {
defer recover()
v := a.codec.decode(reader)
values = append(values, v)
return reader.Len() > 0
}() {
}
return values
}

32
kv/BoolCodec.go Normal file
View File

@ -0,0 +1,32 @@
package kv
import "github.com/tursom/GoCollections/lang"
type (
boolCodec struct {
lang.BaseObject
}
)
var (
TrueBytes = []byte{1}
FalseBytes = []byte{0}
BoolToByteCodec Codec[[]byte, bool] = &boolCodec{}
)
func (b *boolCodec) encode(v2 bool) []byte {
if v2 {
return TrueBytes
} else {
return FalseBytes
}
}
func (b *boolCodec) decode(v1 []byte) bool {
if len(v1) == 0 {
return false
}
return v1[0] != 0
}

26
kv/ChainCodec.go Normal file
View File

@ -0,0 +1,26 @@
package kv
import "github.com/tursom/GoCollections/lang"
type (
chainCodec[V1, V2, V3 any] struct {
lang.BaseObject
codec1 Codec[V2, V3]
codec2 Codec[V1, V2]
}
)
func ChainCodec[V1, V2, V3 any](codec1 Codec[V2, V3], codec2 Codec[V1, V2]) Codec[V1, V3] {
return &chainCodec[V1, V2, V3]{
codec1: codec1,
codec2: codec2,
}
}
func (c *chainCodec[V1, V2, V3]) encode(v2 V3) V1 {
return c.codec2.encode(c.codec1.encode(v2))
}
func (c *chainCodec[V1, V2, V3]) decode(v1 V1) V3 {
return c.codec1.decode(c.codec2.decode(v1))
}

28
kv/MapKvs.go Normal file
View File

@ -0,0 +1,28 @@
package kv
import (
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
)
type (
mapKvs struct {
lang.BaseObject
m map[string][]byte
}
)
func MapKvs() Store[string, []byte] {
return &mapKvs{
m: make(map[string][]byte),
}
}
func (m *mapKvs) Put(key string, value []byte) exceptions.Exception {
m.m[key] = value
return nil
}
func (m *mapKvs) Get(key string) ([]byte, exceptions.Exception) {
return m.m[key], nil
}

16
kv/MapKvs_test.go Normal file
View File

@ -0,0 +1,16 @@
package kv
import (
"fmt"
"testing"
)
func Test_mapKvs(t *testing.T) {
kvs := CodecStore(
MapKvs(),
ByteToStringCodec,
ArrayCodec(ChainCodec(StringToByteCodec, LengthFieldCodec)),
)
_ = kvs.Put([]byte{1}, []string{"hello", "world!"})
fmt.Println(kvs.Get([]byte{1}))
}

235
kv/NumberCodec.go Normal file
View File

@ -0,0 +1,235 @@
package kv
import (
"encoding/binary"
"unsafe"
"github.com/tursom/GoCollections/lang"
)
type (
int8ToByteCodec struct {
lang.BaseObject
}
int16ToByteCodec struct {
lang.BaseObject
}
int32ToByteCodec struct {
lang.BaseObject
}
int64ToByteCodec struct {
lang.BaseObject
}
uint8ToByteCodec struct {
lang.BaseObject
}
uint16ToByteCodec struct {
lang.BaseObject
}
uint32ToByteCodec struct {
lang.BaseObject
}
uint64ToByteCodec struct {
lang.BaseObject
}
float32ToByteCodec struct {
lang.BaseObject
}
float64ToByteCodec struct {
lang.BaseObject
}
complex64ToByteCodec struct {
lang.BaseObject
}
complex128ToByteCodec struct {
lang.BaseObject
}
)
var (
Int8ToByteCodec Codec[[]byte, int8] = &int8ToByteCodec{}
Int16ToByteCodec Codec[[]byte, int16] = &int16ToByteCodec{}
Int32ToByteCodec Codec[[]byte, int32] = &int32ToByteCodec{}
Int64ToByteCodec Codec[[]byte, int64] = &int64ToByteCodec{}
Uint8ToByteCodec Codec[[]byte, uint8] = &uint8ToByteCodec{}
Uint16ToByteCodec Codec[[]byte, uint16] = &uint16ToByteCodec{}
Uint32ToByteCodec Codec[[]byte, uint32] = &uint32ToByteCodec{}
Uint64ToByteCodec Codec[[]byte, uint64] = &uint64ToByteCodec{}
Float32ToByteCodec Codec[[]byte, float32] = &float32ToByteCodec{}
Float64ToByteCodec Codec[[]byte, float64] = &float64ToByteCodec{}
Complex64ToByteCodec Codec[[]byte, complex64] = &complex64ToByteCodec{}
Complex128ToByteCodec Codec[[]byte, complex128] = &complex128ToByteCodec{}
ByteToInt8Codec = InvertCodec[int8, []byte](&int8ToByteCodec{})
ByteToInt16Codec = InvertCodec[int16, []byte](&int16ToByteCodec{})
ByteToInt32Codec = InvertCodec[int32, []byte](&int32ToByteCodec{})
ByteToInt64Codec = InvertCodec[int64, []byte](&int64ToByteCodec{})
ByteToUint8Codec = InvertCodec[uint8, []byte](&uint8ToByteCodec{})
ByteToUint16Codec = InvertCodec[uint16, []byte](&uint16ToByteCodec{})
ByteToUint32Codec = InvertCodec[uint32, []byte](&uint32ToByteCodec{})
ByteToUint64Codec = InvertCodec[uint64, []byte](&uint64ToByteCodec{})
ByteToFloat32Codec = InvertCodec[float32, []byte](&float32ToByteCodec{})
ByteToFloat64Codec = InvertCodec[float64, []byte](&float64ToByteCodec{})
ByteToComplex64Codec = InvertCodec[complex64, []byte](&complex64ToByteCodec{})
ByteToComplex128Codec = InvertCodec[complex128, []byte](&complex128ToByteCodec{})
)
func (u *int8ToByteCodec) encode(v2 int8) []byte {
return []byte{byte(v2)}
}
func (u *int8ToByteCodec) decode(v1 []byte) int8 {
if len(v1) == 0 {
return 0
}
return int8(v1[0])
}
func (u *int16ToByteCodec) encode(v2 int16) []byte {
return binary.BigEndian.AppendUint16(nil, uint16(v2))
}
func (u *int16ToByteCodec) decode(v1 []byte) int16 {
if len(v1) == 0 {
return 0
}
return int16(binary.BigEndian.Uint16(v1))
}
func (u *int32ToByteCodec) encode(v2 int32) []byte {
return binary.BigEndian.AppendUint32(nil, uint32(v2))
}
func (u *int32ToByteCodec) decode(v1 []byte) int32 {
if len(v1) == 0 {
return 0
}
return int32(binary.BigEndian.Uint32(v1))
}
func (u *int64ToByteCodec) encode(v2 int64) []byte {
return binary.BigEndian.AppendUint64(nil, uint64(v2))
}
func (u *int64ToByteCodec) decode(v1 []byte) int64 {
if len(v1) == 0 {
return 0
}
return int64(binary.BigEndian.Uint64(v1))
}
func (u *uint8ToByteCodec) encode(v2 uint8) []byte {
return []byte{v2}
}
func (u *uint8ToByteCodec) decode(v1 []byte) uint8 {
if len(v1) == 0 {
return 0
}
return v1[0]
}
func (u *uint16ToByteCodec) encode(v2 uint16) []byte {
return binary.BigEndian.AppendUint16(nil, v2)
}
func (u *uint16ToByteCodec) decode(v1 []byte) uint16 {
if len(v1) == 0 {
return 0
}
return binary.BigEndian.Uint16(v1)
}
func (u *uint32ToByteCodec) encode(v2 uint32) []byte {
return binary.BigEndian.AppendUint32(nil, v2)
}
func (u *uint32ToByteCodec) decode(v1 []byte) uint32 {
if len(v1) == 0 {
return 0
}
return binary.BigEndian.Uint32(v1)
}
func (u *uint64ToByteCodec) encode(v2 uint64) []byte {
return binary.BigEndian.AppendUint64(nil, v2)
}
func (u *uint64ToByteCodec) decode(v1 []byte) uint64 {
if len(v1) == 0 {
return 0
}
return binary.BigEndian.Uint64(v1)
}
func (u *float32ToByteCodec) encode(v2 float32) []byte {
return binary.BigEndian.AppendUint32(nil, *(*uint32)(unsafe.Pointer(&v2)))
}
func (u *float32ToByteCodec) decode(v1 []byte) float32 {
if len(v1) == 0 {
return 0
}
u2 := binary.BigEndian.Uint32(v1)
return *(*float32)(unsafe.Pointer(&u2))
}
func (u *float64ToByteCodec) encode(v2 float64) []byte {
return binary.BigEndian.AppendUint64(nil, *(*uint64)(unsafe.Pointer(&v2)))
}
func (u *float64ToByteCodec) decode(v1 []byte) float64 {
if len(v1) == 0 {
return 0
}
u2 := binary.BigEndian.Uint64(v1)
return *(*float64)(unsafe.Pointer(&u2))
}
func (u *complex64ToByteCodec) encode(v2 complex64) []byte {
return binary.BigEndian.AppendUint64(nil, *(*uint64)(unsafe.Pointer(&v2)))
}
func (u *complex64ToByteCodec) decode(v1 []byte) complex64 {
if len(v1) == 0 {
return 0
}
u2 := binary.BigEndian.Uint64(v1)
return *(*complex64)(unsafe.Pointer(&u2))
}
func (u *complex128ToByteCodec) encode(v2 complex128) []byte {
r := real(v2)
i := imag(v2)
bytes := make([]byte, 16)
binary.BigEndian.PutUint64(bytes[0:], *(*uint64)(unsafe.Pointer(&r)))
binary.BigEndian.PutUint64(bytes[8:], *(*uint64)(unsafe.Pointer(&i)))
return bytes
}
func (u *complex128ToByteCodec) decode(v1 []byte) complex128 {
if len(v1) == 0 {
return 0
}
r := binary.BigEndian.Uint64(v1[0:])
i := binary.BigEndian.Uint64(v1[8:])
return complex(
*(*float64)(unsafe.Pointer(&r)),
*(*float64)(unsafe.Pointer(&i)),
)
}

41
kv/ProtoCodec.go Normal file
View File

@ -0,0 +1,41 @@
package kv
import (
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
"google.golang.org/protobuf/proto"
)
type (
protoToByteCodec[V proto.Message] struct {
lang.BaseObject
emptyMessage func() V
}
)
func ProtoCodec[V proto.Message](emptyMessage func() V) Codec[[]byte, V] {
return &protoToByteCodec[V]{
emptyMessage: emptyMessage,
}
}
func ProtoDeCodec[V proto.Message](emptyMessage func() V) Codec[V, []byte] {
return InvertCodec(ProtoCodec(emptyMessage))
}
func (p *protoToByteCodec[V]) encode(v2 V) []byte {
bytes, err := proto.Marshal(v2)
if err == nil {
panic(exceptions.Package(err))
}
return bytes
}
func (p *protoToByteCodec[V]) decode(v1 []byte) V {
message := p.emptyMessage()
if err := proto.Unmarshal(v1, message); err != nil {
panic(exceptions.Package(err))
}
return message
}

91
kv/ReaderCodec.go Normal file
View File

@ -0,0 +1,91 @@
package kv
import (
"bytes"
"encoding/binary"
"io"
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
)
// 不推荐使用
type (
readerCodec[V any] struct {
lang.BaseObject
codec Codec[[]byte, V]
}
fixedLengthCodec struct {
lang.BaseObject
frameLength uint32
}
lengthFieldCodec struct {
lang.BaseObject
}
)
var (
LengthFieldCodec Codec[io.Reader, []byte] = &lengthFieldCodec{}
)
func ReaderCodec[V any](codec Codec[[]byte, V]) Codec[io.Reader, V] {
return &readerCodec[V]{
codec: codec,
}
}
func FixedLengthCodec(frameLength uint32) Codec[io.Reader, []byte] {
return &fixedLengthCodec{frameLength: frameLength}
}
func (r *readerCodec[V]) encode(v2 V) io.Reader {
return bytes.NewReader(r.codec.encode(v2))
}
func (r *readerCodec[V]) decode(v1 io.Reader) V {
all, err := io.ReadAll(v1)
if err != nil {
panic(exceptions.Package(err))
}
return r.codec.decode(all)
}
func (f *fixedLengthCodec) encode(v2 []byte) io.Reader {
return bytes.NewReader(v2)
}
func (f *fixedLengthCodec) decode(v1 io.Reader) []byte {
bs := make([]byte, f.frameLength)
n, err := v1.Read(bs)
if err != nil {
panic(exceptions.Package(err))
}
return bs[0:n]
}
func (l *lengthFieldCodec) encode(v2 []byte) io.Reader {
buffer := bytes.NewBuffer(nil)
_ = binary.Write(buffer, binary.BigEndian, uint32(len(v2)))
buffer.Write(v2)
return buffer
}
func (l *lengthFieldCodec) decode(v1 io.Reader) []byte {
var length uint32
if err := binary.Read(v1, binary.BigEndian, &length); err != nil {
panic(exceptions.Package(err))
}
bs := make([]byte, length)
n, err := v1.Read(bs)
if err != nil {
panic(exceptions.Package(err))
}
return bs[0:n]
}

26
kv/StringCodec.go Normal file
View File

@ -0,0 +1,26 @@
package kv
import "github.com/tursom/GoCollections/lang"
type (
stringToByteCodec struct {
lang.BaseObject
}
)
var (
StringToByteCodec Codec[[]byte, string] = &stringToByteCodec{}
ByteToStringCodec = InvertCodec[string, []byte](&stringToByteCodec{})
)
func (s *stringToByteCodec) encode(v2 string) []byte {
return []byte(v2)
}
func (s *stringToByteCodec) decode(v1 []byte) string {
if len(v1) == 0 {
return ""
}
return string(v1)
}

116
kv/codec.go Normal file
View File

@ -0,0 +1,116 @@
package kv
import (
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
)
type (
Codec[V1, V2 any] interface {
lang.Object
encode(v2 V2) V1
decode(v1 V1) V2
}
codecStore[K1, K2, V1, V2 any] struct {
lang.BaseObject
kvs Store[K1, V1]
kCodec Codec[K1, K2]
vCodec Codec[V1, V2]
}
kCodecStore[K1, K2, V any] struct {
lang.BaseObject
kvs Store[K1, V]
codec Codec[K1, K2]
}
vCodecStore[K, V1, V2 any] struct {
lang.BaseObject
kvs Store[K, V1]
codec Codec[V1, V2]
}
invertCodec[V1, V2 any] struct {
lang.BaseObject
codec Codec[V2, V1]
}
)
func InvertCodec[V1, V2 any](codec Codec[V2, V1]) Codec[V1, V2] {
return &invertCodec[V1, V2]{codec: codec}
}
func CodecStore[K1, K2, V1, V2 any](
kvs Store[K1, V1],
kCodec Codec[K1, K2],
vCodec Codec[V1, V2],
) Store[K2, V2] {
return &codecStore[K1, K2, V1, V2]{
kvs: kvs,
kCodec: kCodec,
vCodec: vCodec,
}
}
func KCodecStore[K1, K2, V any](
kvs Store[K1, V],
codec Codec[K1, K2],
) Store[K2, V] {
return &kCodecStore[K1, K2, V]{
kvs: kvs,
codec: codec,
}
}
func VCodecStore[K, V1, V2 any](
kvs Store[K, V1],
codec Codec[V1, V2],
) Store[K, V2] {
return &vCodecStore[K, V1, V2]{
kvs: kvs,
codec: codec,
}
}
func (c *codecStore[K1, K2, V1, V2]) Put(key K2, value V2) exceptions.Exception {
return c.kvs.Put(c.kCodec.encode(key), c.vCodec.encode(value))
}
func (c *codecStore[K1, K2, V1, V2]) Get(key K2) (V2, exceptions.Exception) {
value, exception := c.kvs.Get(c.kCodec.encode(key))
if exception != nil {
return lang.Nil[V2](), exception
}
return c.vCodec.decode(value), nil
}
func (c *kCodecStore[K1, K2, V]) Put(key K2, value V) exceptions.Exception {
return c.kvs.Put(c.codec.encode(key), value)
}
func (c *kCodecStore[K1, K2, V]) Get(key K2) (V, exceptions.Exception) {
return c.kvs.Get(c.codec.encode(key))
}
func (c *vCodecStore[K, V1, V2]) Put(key K, value V2) exceptions.Exception {
return c.kvs.Put(key, c.codec.encode(value))
}
func (c *vCodecStore[K, V1, V2]) Get(key K) (V2, exceptions.Exception) {
get, exception := c.kvs.Get(key)
if exception != nil {
return lang.Nil[V2](), exception
}
return c.codec.decode(get), nil
}
func (i *invertCodec[V1, V2]) encode(v2 V2) V1 {
return i.codec.decode(v2)
}
func (i *invertCodec[V1, V2]) decode(v1 V1) V2 {
return i.codec.encode(v1)
}

14
kv/kvs.go Normal file
View File

@ -0,0 +1,14 @@
package kv
import (
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
)
type (
Store[K, V any] interface {
lang.Object
Put(key K, value V) exceptions.Exception
Get(key K) (V, exceptions.Exception)
}
)

37
leveldb/leveldb.go Normal file
View File

@ -0,0 +1,37 @@
package leveldb
import (
"github.com/syndtr/goleveldb/leveldb"
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
"kvs/kv"
)
type (
leveldbKVS struct {
lang.BaseObject
db *leveldb.DB
}
)
func New(db *leveldb.DB) kv.Store[[]byte, []byte] {
return &leveldbKVS{db: db}
}
func (l *leveldbKVS) Put(key []byte, value []byte) exceptions.Exception {
if err := l.db.Put(key, value, nil); err != nil {
return exceptions.Package(err)
}
return nil
}
func (l *leveldbKVS) Get(key []byte) ([]byte, exceptions.Exception) {
value, err := l.db.Get(key, nil)
if err != nil {
return nil, exceptions.Package(err)
}
return value, nil
}

27
leveldb/leveldb_test.go Normal file
View File

@ -0,0 +1,27 @@
package leveldb
import (
"testing"
"github.com/syndtr/goleveldb/leveldb"
"kvs/kv"
)
func Test_leveldbKVS(t *testing.T) {
db, err := leveldb.OpenFile("test", nil)
if err != nil {
t.Fatal(err)
}
s := kv.CodecStore(New(db), kv.StringToByteCodec, kv.StringToByteCodec)
if err := s.Put("hello", "world!"); err != nil {
t.Fatal(err)
}
value, exception := s.Get("hello")
if exception != nil || value != "world!" {
t.Fatal(value, exception)
}
}

11
pipe/pipe.go Normal file
View File

@ -0,0 +1,11 @@
package pipe
import "github.com/tursom/GoCollections/lang"
type (
PipelineHandler[V1, V2 any] interface {
lang.Object
encode1(input []V1) []V2
encode2(input []V2) []V1
}
)

90
sqlite/sqlite.go Normal file
View File

@ -0,0 +1,90 @@
package sqlite
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
"kvs/kv"
)
type (
sqliteKVS struct {
lang.BaseObject
db *sql.DB
table string
}
)
func New(db *sql.DB, table string) (kv.Store[[]byte, []byte], exceptions.Exception) {
kvs := &sqliteKVS{
db: db,
table: table,
}
if err := kvs.createTable(); err != nil {
return nil, err
}
return kvs, nil
}
func (s *sqliteKVS) createTable() exceptions.Exception {
if _, err := s.db.Exec("create table if not exists " + s.table + " (" +
"k blob primary key not null," +
"v blob" +
")"); err != nil {
return exceptions.Package(err)
}
return nil
}
func (s *sqliteKVS) Get(key []byte) ([]byte, exceptions.Exception) {
rows, err := s.db.Query("select v from "+s.table+" where k = ?", key)
if err != nil {
return nil, exceptions.Package(err)
}
defer rows.Close()
if !rows.Next() {
return nil, nil
}
var data []byte
err = rows.Scan(&data)
if err != nil {
return nil, exceptions.Package(err)
}
return data, nil
}
func (s *sqliteKVS) Put(key []byte, value []byte) exceptions.Exception {
if value == nil {
value = []byte{}
}
exec, err := s.db.Exec("update "+s.table+" set v=? where k=?", value, key)
if err != nil {
return exceptions.Package(err)
}
affected, err := exec.RowsAffected()
if err != nil {
return exceptions.Package(err)
}
if affected != 0 {
return nil
}
if _, err = s.db.Exec("insert into "+s.table+" (k,v) values (?,?)", key, value); err != nil {
return exceptions.Package(err)
}
return nil
}

30
sqlite/sqlite_test.go Normal file
View File

@ -0,0 +1,30 @@
package sqlite
import (
"database/sql"
"testing"
_ "github.com/mattn/go-sqlite3"
"github.com/tursom/GoCollections/exceptions"
"kvs/kv"
)
func Test_sqliteKVS(t *testing.T) {
db := exceptions.Exec2r1(sql.Open, "sqlite3", ":memory:")
s, exception := New(db, "kv")
if exception != nil {
t.Fatal(exception)
}
skvs := kv.CodecStore(s, kv.StringToByteCodec, kv.StringToByteCodec)
if err := skvs.Put("hello", "world!"); err != nil {
t.Fatal(err)
}
value, exception := skvs.Get("hello")
if exception != nil || value != "world!" {
t.Fatal(value, exception)
}
}