单双表
This commit is contained in:
parent
43af97a8d5
commit
8f000ad9cd
89
README.md
89
README.md
@ -1,2 +1,91 @@
|
||||
# to_entangle
|
||||
由go语言实现数据的双向绑定
|
||||
|
||||
|
||||
`go get github.com/InvisibleFuture/to_entangle`
|
||||
|
||||
|
||||
### 双表映射
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
toentangle "github.com/InvisibleFuture/to_entangle"
|
||||
)
|
||||
|
||||
// 创建一个 Entangle
|
||||
entangle := NewToEntangle("data/test")
|
||||
|
||||
// 添加一对数据, 使其双向绑定
|
||||
entangle.Add("a", "b")
|
||||
entangle.Add("a", "c")
|
||||
|
||||
// 获取 a 的全部绑定数据
|
||||
arr, _ := entangle.Get("a")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 获取 b 的全部绑定数据
|
||||
arr, _ = entangle.Get("b")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 获取 c 的全部绑定数据
|
||||
arr, _ = entangle.Get("c")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 移除所有绑定
|
||||
entangle.Remove("a", "b")
|
||||
entangle.Remove("a", "c")
|
||||
|
||||
// 获取 a 的全部绑定数据
|
||||
arr, _ = entangle.Get("a")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 获取 s 的全部绑定数据
|
||||
arr, _ = entangle.Get("s")
|
||||
fmt.Println(arr)
|
||||
|
||||
```
|
||||
|
||||
|
||||
### 单表映射
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
toentangle "github.com/InvisibleFuture/to_entangle"
|
||||
)
|
||||
|
||||
// 创建一个 Entangle
|
||||
entangle := NewEntangle("data/test")
|
||||
|
||||
// 添加一对数据, 使其双向绑定
|
||||
entangle.Add("a", "b")
|
||||
entangle.Add("a", "c")
|
||||
|
||||
// 获取 a 的全部绑定数据
|
||||
arr, _ := entangle.Get("a")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 获取 b 的全部绑定数据
|
||||
arr, _ = entangle.Get("b")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 获取 c 的全部绑定数据
|
||||
arr, _ = entangle.Get("c")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 移除所有绑定
|
||||
entangle.Remove("a", "b")
|
||||
entangle.Remove("a", "c")
|
||||
|
||||
// 获取 a 的全部绑定数据
|
||||
arr, _ = entangle.Get("a")
|
||||
fmt.Println(arr)
|
||||
|
||||
// 获取 s 的全部绑定数据
|
||||
arr, _ = entangle.Get("s")
|
||||
fmt.Println(arr)
|
||||
|
||||
```
|
||||
|
@ -7,19 +7,19 @@ import (
|
||||
leveldb "github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
// 单表之内的双向绑定
|
||||
// 1. 存入一对数据, 使其双向绑定
|
||||
// 2. 移除一对数据, 使其双向解绑
|
||||
// 3. 移除一个数据, 使其全部解绑
|
||||
// 4. 获取一个数据的全部绑定数据
|
||||
|
||||
type ToEntangle struct {
|
||||
type Entangle struct {
|
||||
lock sync.Mutex
|
||||
db *leveldb.DB
|
||||
}
|
||||
|
||||
// Get 获取一个数据的全部绑定数据
|
||||
func (t *ToEntangle) Get(a string) (arr []string, err error) {
|
||||
// 获取 a 的数据, 如果不存在, 则直接返回空数组
|
||||
func (t *Entangle) Get(a string) (arr []string, err error) {
|
||||
data, err := t.db.Get([]byte(a), nil)
|
||||
if err != nil {
|
||||
if err == leveldb.ErrNotFound {
|
||||
@ -27,8 +27,6 @@ func (t *ToEntangle) Get(a string) (arr []string, err error) {
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// data 为json字符串的数组, 解码后返回
|
||||
err = jsoniter.Unmarshal(data, &arr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -37,7 +35,7 @@ func (t *ToEntangle) Get(a string) (arr []string, err error) {
|
||||
}
|
||||
|
||||
// Add 添加一对数据, 使其双向绑定
|
||||
func (t *ToEntangle) Add(a string, b string) (err error) {
|
||||
func (t *Entangle) Add(a string, b string) (err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
@ -90,7 +88,7 @@ func (t *ToEntangle) Add(a string, b string) (err error) {
|
||||
}
|
||||
|
||||
// 单向解绑
|
||||
func (t *ToEntangle) remove_item(a string, b string) (err error) {
|
||||
func (t *Entangle) remove_item(a string, b string) (err error) {
|
||||
// 获取 a 的数据, 如果不存在, 则直接返回
|
||||
data, err := t.db.Get([]byte(a), nil)
|
||||
if err != nil {
|
||||
@ -126,7 +124,7 @@ func (t *ToEntangle) remove_item(a string, b string) (err error) {
|
||||
}
|
||||
|
||||
// Remove 移除一对数据, 使其双向解绑
|
||||
func (t *ToEntangle) Remove(a string, b string) (err error) {
|
||||
func (t *Entangle) Remove(a string, b string) (err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
@ -141,7 +139,7 @@ func (t *ToEntangle) Remove(a string, b string) (err error) {
|
||||
}
|
||||
|
||||
// RemoveAll 移除一个数据, 使其全部解绑
|
||||
func (t *ToEntangle) RemoveAll(a string) (err error) {
|
||||
func (t *Entangle) RemoveAll(a string) (err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
@ -174,18 +172,18 @@ func (t *ToEntangle) RemoveAll(a string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// New 创建一个 ToEntangle
|
||||
func New(path string) *ToEntangle {
|
||||
// New 创建一个 Entangle
|
||||
func NewEntangle(path string) *Entangle {
|
||||
db, err := leveldb.OpenFile(path, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &ToEntangle{
|
||||
return &Entangle{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Close 关闭 leveldb
|
||||
func (t *ToEntangle) Close() {
|
||||
func (t *Entangle) Close() {
|
||||
t.db.Close()
|
||||
}
|
@ -6,9 +6,9 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToEntangle_Get(t *testing.T) {
|
||||
// 创建一个 ToEntangle
|
||||
entangle := New("data")
|
||||
func TestEntangle_Get(t *testing.T) {
|
||||
// 创建一个 Entangle
|
||||
entangle := NewEntangle("data")
|
||||
|
||||
// 添加一对数据, 使其双向绑定
|
||||
entangle.Add("a", "b")
|
61
toentangle._test.go
Normal file
61
toentangle._test.go
Normal file
@ -0,0 +1,61 @@
|
||||
package toentangle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToEntangle_Get(t *testing.T) {
|
||||
// 创建一个 ToEntangle
|
||||
toentangle := NewToEntangle("data")
|
||||
|
||||
// 添加一对数据, 使其双向绑定
|
||||
toentangle.Add("a", "b")
|
||||
toentangle.Add("a", "c")
|
||||
|
||||
// 获取 a 的全部绑定数据
|
||||
arr, _ := toentangle.GetA("a")
|
||||
fmt.Println(arr)
|
||||
if len(arr) != 2 {
|
||||
t.Errorf("GetA(\"a\") = %v; want [\"b\", \"c\"]", arr)
|
||||
}
|
||||
|
||||
// 获取 b 的全部绑定数据
|
||||
arr, _ = toentangle.GetB("b")
|
||||
fmt.Println(arr)
|
||||
if len(arr) != 1 || arr[0] != "a" {
|
||||
t.Errorf("GetB(\"b\") = %v; want [\"a\"]", arr)
|
||||
}
|
||||
|
||||
// 获取 c 的全部绑定数据
|
||||
arr, _ = toentangle.GetB("c")
|
||||
fmt.Println(arr)
|
||||
if len(arr) != 1 || arr[0] != "a" {
|
||||
t.Errorf("GetB(\"c\") = %v; want [\"a\"]", arr)
|
||||
}
|
||||
|
||||
// 移除所有绑定
|
||||
toentangle.Remove("a", "b")
|
||||
toentangle.Remove("a", "c")
|
||||
|
||||
// 获取 a 的全部绑定数据
|
||||
arr, _ = toentangle.GetA("a")
|
||||
fmt.Println(arr)
|
||||
if len(arr) != 0 {
|
||||
t.Errorf("GetA(\"a\") = %v; want []", arr)
|
||||
}
|
||||
|
||||
// 获取 s 的全部绑定数据
|
||||
arr, _ = toentangle.GetB("s")
|
||||
fmt.Println(arr)
|
||||
if len(arr) != 0 {
|
||||
t.Errorf("GetB(\"s\") = %v; want []", arr)
|
||||
}
|
||||
|
||||
// 清理 leveldb
|
||||
toentangle.Close()
|
||||
|
||||
// 删除 data 文件夹
|
||||
os.RemoveAll("data")
|
||||
}
|
236
toentangle.go
Normal file
236
toentangle.go
Normal file
@ -0,0 +1,236 @@
|
||||
package toentangle
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
leveldb "github.com/syndtr/goleveldb/leveldb"
|
||||
)
|
||||
|
||||
// 两表之间的双向绑定
|
||||
// 1. 存入一对数据, 使其双向绑定
|
||||
// 2. 移除一对数据, 使其双向解绑
|
||||
// 3. 移除一个数据, 使其全部解绑
|
||||
// 4. 获取一个数据的全部绑定数据
|
||||
|
||||
type ToEntangle struct {
|
||||
lock sync.Mutex
|
||||
dba *leveldb.DB
|
||||
dbb *leveldb.DB
|
||||
}
|
||||
|
||||
// GetA 获取一个数据的全部绑定数据
|
||||
func (t *ToEntangle) GetA(a string) (arr []string, err error) {
|
||||
// 获取 a 的数据, 如果不存在, 则直接返回空数组
|
||||
data, err := t.dba.Get([]byte(a), nil)
|
||||
if err != nil {
|
||||
if err == leveldb.ErrNotFound {
|
||||
return []string{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// data 为json字符串的数组, 解码后返回
|
||||
err = jsoniter.Unmarshal(data, &arr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
// GetB 获取一个数据的全部绑定数据
|
||||
func (t *ToEntangle) GetB(b string) (arr []string, err error) {
|
||||
// 获取 b 的数据, 如果不存在, 则直接返回空数组
|
||||
data, err := t.dbb.Get([]byte(b), nil)
|
||||
if err != nil {
|
||||
if err == leveldb.ErrNotFound {
|
||||
return []string{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
err = jsoniter.Unmarshal(data, &arr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
// Add 添加一对数据, 使其双向绑定
|
||||
func (t *ToEntangle) Add(a string, b string) (err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
var set_data = func(a string, b string, db *leveldb.DB) (err error) {
|
||||
data, err := db.Get([]byte(a), nil)
|
||||
if err != nil {
|
||||
if err == leveldb.ErrNotFound {
|
||||
data, _ = jsoniter.Marshal([]string{b})
|
||||
return db.Put([]byte(a), data, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
// data 为json字符串的数组, 解码后添加 b
|
||||
var arr []string
|
||||
err = jsoniter.Unmarshal(data, &arr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 转换为 map, 添加 b, 以去重
|
||||
m := make(map[string]bool)
|
||||
for _, v := range arr {
|
||||
m[v] = true
|
||||
}
|
||||
m[b] = true
|
||||
|
||||
// 转换回数组
|
||||
arr = make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
arr = append(arr, k)
|
||||
}
|
||||
|
||||
// 编码后存入
|
||||
data, _ = jsoniter.Marshal(arr)
|
||||
return db.Put([]byte(a), data, nil)
|
||||
}
|
||||
|
||||
// 设置 a 的数据
|
||||
err = set_data(a, b, t.dba)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 设置 b 的数据
|
||||
return set_data(b, a, t.dbb)
|
||||
}
|
||||
|
||||
// 单向解绑
|
||||
func (t *ToEntangle) remove(a string, b string, db *leveldb.DB) (err error) {
|
||||
data, err := db.Get([]byte(a), nil)
|
||||
if err != nil {
|
||||
if err == leveldb.ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// data 为json字符串的数组, 解码后删除 b
|
||||
var arr []string
|
||||
err = jsoniter.Unmarshal(data, &arr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 转换为 map, 删除 b
|
||||
m := make(map[string]bool)
|
||||
for _, v := range arr {
|
||||
m[v] = true
|
||||
}
|
||||
delete(m, b)
|
||||
|
||||
// 转换回数组
|
||||
arr = make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
arr = append(arr, k)
|
||||
}
|
||||
|
||||
// 编码后存入
|
||||
data, _ = jsoniter.Marshal(arr)
|
||||
return db.Put([]byte(a), data, nil)
|
||||
}
|
||||
|
||||
// Remove 移除一对数据, 使其双向解绑
|
||||
func (t *ToEntangle) Remove(a string, b string) (err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
// 移除 a 的数据
|
||||
err = t.remove(a, b, t.dba)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 移除 b 的数据
|
||||
return t.remove(b, a, t.dbb)
|
||||
}
|
||||
|
||||
// RemoveA 移除一个数据, 使其全部解绑
|
||||
func (t *ToEntangle) RemoveA(a string) (err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
// 获取 a 的数据
|
||||
data, err := t.dba.Get([]byte(a), nil)
|
||||
if err != nil {
|
||||
if err == leveldb.ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// data 为json字符串的数组, 解码后删除全部数据
|
||||
var arr []string
|
||||
err = jsoniter.Unmarshal(data, &arr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除全部数据
|
||||
for _, v := range arr {
|
||||
err = t.remove(a, v, t.dbb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 删除 a 的数据
|
||||
return t.dba.Delete([]byte(a), nil)
|
||||
}
|
||||
|
||||
// RemoveB 移除一个数据, 使其全部解绑
|
||||
func (t *ToEntangle) RemoveB(b string) (err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
// 获取 b 的数据
|
||||
data, err := t.dbb.Get([]byte(b), nil)
|
||||
if err != nil {
|
||||
if err == leveldb.ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// data 为json字符串的数组, 解码后删除全部数据
|
||||
var arr []string
|
||||
err = jsoniter.Unmarshal(data, &arr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除全部数据
|
||||
for _, v := range arr {
|
||||
err = t.remove(b, v, t.dba)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 删除 b 的数据
|
||||
return t.dbb.Delete([]byte(b), nil)
|
||||
}
|
||||
|
||||
// New 创建一个双向绑定 ToEntangle
|
||||
func NewToEntangle(path string) *ToEntangle {
|
||||
dba, _ := leveldb.OpenFile(path+"/a", nil)
|
||||
dbb, _ := leveldb.OpenFile(path+"/b", nil)
|
||||
return &ToEntangle{
|
||||
dba: dba,
|
||||
dbb: dbb,
|
||||
}
|
||||
}
|
||||
|
||||
// Close 关闭 leveldb
|
||||
func (t *ToEntangle) Close() {
|
||||
t.dba.Close()
|
||||
t.dbb.Close()
|
||||
}
|
Loading…
Reference in New Issue
Block a user