package toentangle import ( "sync" jsoniter "github.com/json-iterator/go" leveldb "github.com/syndtr/goleveldb/leveldb" ) // 单表之内的双向绑定 // 1. 存入一对数据, 使其双向绑定 // 2. 移除一对数据, 使其双向解绑 // 3. 移除一个数据, 使其全部解绑 // 4. 获取一个数据的全部绑定数据 type Entangle struct { lock sync.Mutex db *leveldb.DB } // Get 获取一个数据的全部绑定数据 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 { return []string{}, nil } return nil, err } err = jsoniter.Unmarshal(data, &arr) if err != nil { return nil, err } return arr, nil } // Add 添加一对数据, 使其双向绑定 func (t *Entangle) Add(a string, b string) (err error) { t.lock.Lock() defer t.lock.Unlock() var set_data = func(a string, b string) (err error) { // 获取 a 的数据 data, err := t.db.Get([]byte(a), nil) if err != nil { // 如果不存在, 则创建并直接添加 b if err == leveldb.ErrNotFound { data, _ = jsoniter.Marshal([]string{b}) return t.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 t.db.Put([]byte(a), data, nil) } err = set_data(a, b) if err != nil { return err } err = set_data(b, a) if err != nil { return err } return err } // 单向解绑 func (t *Entangle) remove_item(a string, b string) (err error) { // 获取 a 的数据, 如果不存在, 则直接返回 data, err := t.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 } // 如果只有一个, 则直接移除条目 if len(arr) == 1 { return t.db.Delete([]byte(a), nil) } // 直接遍历移除 for i, v := range arr { if v == b { arr = append(arr[:i], arr[i+1:]...) break } } // 重新编码后存入 data, _ = jsoniter.Marshal(arr) return t.db.Put([]byte(a), data, nil) } // Remove 移除一对数据, 使其双向解绑 func (t *Entangle) Remove(a string, b string) (err error) { t.lock.Lock() defer t.lock.Unlock() if err = t.remove_item(a, b); err != nil { return err } if err = t.remove_item(b, a); err != nil { return err } return err } // RemoveAll 移除一个数据, 使其全部解绑 func (t *Entangle) RemoveAll(a string) (err error) { t.lock.Lock() defer t.lock.Unlock() // 获取 a 的数据 data, err := t.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 } // 遍历移除 for _, v := range arr { if err = t.remove_item(a, v); err != nil { return err } if err = t.remove_item(v, a); err != nil { return err } } return nil } // New 创建一个 Entangle func NewEntangle(path string) *Entangle { db, err := leveldb.OpenFile(path, nil) if err != nil { panic(err) } return &Entangle{ db: db, } } // Close 关闭 leveldb func (t *Entangle) Close() { t.db.Close() }